Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang sorting slice of IP addresses as strings

Tags:

sorting

go

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
like image 443
Devin Avatar asked Jan 22 '18 20:01

Devin


People also ask

How do you sort slices in go?

In Go language, you can sort a slice with the help of Slice() function. This function sorts the specified slice given the provided less function. The result of this function is not stable. So for stable sort, you can use SliceStable.

How does sort slice work Golang?

You simply pass an anonymous function to the sort. Slice function. This will sort in ascending order, if you want the opposite, simply write a[i] > a[j] in the anonymous function. @LewisChan it is not restricted on int types; the int parameters are indexes to the slice, which can be a slice of strings.

What is IP Sorting?

Approach: The idea is to use a custom comparator to sort the given IP addresses. Since IPv4 has 4 octets, we will compare the addresses octet by octet. Check the first octet of the IP Address, If the first address has a greater first octet, then return True to swap the IP address, otherwise, return False.

What sorting does Golang use?

Golang has a built-in sort function that can be used to sort slices of strings, integers, and floating-point numbers. Sorting is done using one of these functions: sort. Ints.


Video Answer


1 Answers

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.

like image 53
Adrian Avatar answered Oct 13 '22 07:10

Adrian