golang sorting slice of IP addresses as strings

Issue

I’m looking to sort a slice of IP addresses (only IPV4) in Golang.

Using the native sort package using sort.Strings() doesn’t work for obvious reasons since naturally 192.168.4.41 would be sorted in front of 192.168.4.5

By sorting the numerical value of an IP alongside the IP string in a map I came up with a way to achieve it, but it feels too manual. Is this the most efficient way to break up the IP string and sort the addresses?

https://play.golang.org/p/FUYQKuhgUq8

package main

import (
  "fmt"
  "strconv"
  "strings"
  "sort"
)

func main() {
  ips := []string{
    "192.168.1.5",
    "69.52.220.44",
    "10.152.16.23",
    "192.168.3.10",
    "192.168.1.4",
    "192.168.1.41",
    }

ipsWithInt := make(map[string]int64)

for _, ip := range ips {
    ipStr := strings.Split(ip, ".")

    oct0, _ := strconv.ParseInt(ipStr[0], 10, 64)
    ipInt0 := oct0 * 255 * 255 * 255

    oct1, _ := strconv.ParseInt(ipStr[1], 10, 64)
    ipInt1 := oct1 * 255 * 255

    oct2, _ := strconv.ParseInt(ipStr[2], 10, 64)
    ipInt2 := oct2 * 255

    oct3, _ := strconv.ParseInt(ipStr[3], 10, 64)
    ipInt3 := oct3

    ipInt := ipInt0 + ipInt1 + ipInt2 + ipInt3

    ipsWithInt[ip] = ipInt
  }


  type kv struct {
    Key   string
    Value int64
  }

  var ss []kv
  for k, v := range ipsWithInt {
    ss = append(ss, kv{k, v})
  }

  sort.Slice(ss, func(i, j int) bool {
    return ss[i].Value < ss[j].Value
  })


  for _, kv := range ss {
    fmt.Printf("%s\n", kv.Key)
  }
}

Results:

10.152.16.23
69.52.220.44
192.168.1.4
192.168.1.5
192.168.1.41
192.168.3.10

Solution

There are lots of possible ways to do it, but the easiest that comes quickly to mind would be to parse them into net.IPs (which are just byte slices, a more accurate representation of an IP), and then sort those:

realIPs := make([]net.IP, 0, len(ips))

for _, ip := range ips {
    realIPs = append(realIPs, net.ParseIP(ip))
}

sort.Slice(realIPs, func(i, j int) bool {
    return bytes.Compare(realIPs[i], realIPs[j]) < 0
})

Working example here: https://play.golang.org/p/UtuvVz44_c8

This has the added advantage of working equally well with IPv6 addresses with no modifications.

Answered By – Adrian

Answer Checked By – Senaida (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.