0

I have a list of ip objects that have their v4 address as a String. (ip is in decimal)

Now I want to sort this list in ascending order with the ip parts as search keys.

This was my first approach. It works but it needs four functions to return each part of the ip.

Comparator<IP> ipComparator =
  Comparator
  .comparing(IP::getFirstPart)
  .thenComparing(IP::getSecondPart)
  .thenComparing(IP::getThirdPart)
  .thenComparing(IP::getFourthPart);

I would like to do something like this

Comparator<IP> ipComparator =
  Comparator
  .comparing(IP::getPart(0))
  .thenComparing(IP::getPart(1))
  .thenComparing(IP::getPart(2))
  .thenComparing(IP::getPart(3));

What is the easiest way to implement this without defining a function to return each part of the ip?

trsommer
  • 5
  • 2
  • 2
    An IP address is just a representation of a 32 bit integer. You can [convert them to numbers](https://stackoverflow.com/questions/12057853/how-to-convert-string-ip-numbers-to-integer-in-java) for sorting. – user229044 Feb 27 '22 at 02:50

2 Answers2

0

If you represent them as a natural string like "192.168.2.4", then they won't be sortable, but if you zero-prefix each octet like, "192.168.002.004" then the strings will sort as expected. Similarly, you can represent them in hexadecimal like, "C0A80204". The key is fixed width per octet.

Alternatively, you can represent the 4 octets as a single number. The thing to be careful of is that if the first octet is 127 or higher, then a 32-bit integer will treat it as a negative number, which will affect the sort order. The easiest solution (if not the most memory-efficient) is to return it as a long value.

phatfingers
  • 9,770
  • 3
  • 30
  • 44
0

Here is one way to do it.

  • create a list to hold the ip addresses.
List<InetAddress> ips = new ArrayList<>();

Then create some to sort. I am demonstrating the Inet4Address class to accept either a dotted quad or a byte array. Then shuffle the list.

for (int i = 1; i < 23; i+= 2) {
    ips.add(Inet4Address.getByName("192.168.1."+i));
    ips.add(Inet4Address.getByAddress(new byte[]{(byte)192, (byte)168, 
                                                 (byte)1, (byte)(i+1)}));
}
Collections.shuffle(ips);

According to the source code the hashCode for Inet4Address is the address itself. And that could be used for sorting without using a key extractor. But as far as I can tell it is not documented and therefore should not be relied upon. So it can be done as follows:

  • use a ByteBuffer to wrap the byte array returned from getAddress() and retrieve the int value.
  • then. since the high order bit can arbitrarily appear in IP addresses, do an unsigned compare on the two ip's as applied by the sort
ips.sort(Comparator.comparing(ip->
            ByteBuffer.wrap(ip.getAddress()).getInt(),
            (i1, i2) -> Integer.compareUnsigned(i1, i2)));

Now print the results.

ips.forEach(ip->System.out.println(ip.getHostAddress()));

prints

192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.5
192.168.1.6
192.168.1.7
192.168.1.8
192.168.1.9
192.168.1.10
192.168.1.11
192.168.1.12
192.168.1.13
192.168.1.14
192.168.1.15
192.168.1.16
192.168.1.17
192.168.1.18
192.168.1.19
192.168.1.20
192.168.1.21
192.168.1.22
WJS
  • 36,363
  • 4
  • 24
  • 39