Java sort ip address

How to sort ip address in ascending order

So far I use HashMap to stored my data. I want sort the value by the Ip address in ascending order. Seems TreeMap is better choice?

Create a comparator that splits the string and compares each of the 4 parts as ints. Should be pretty straightforward.

10 Answers 10

Don’t rewrite the wheel like I tried too, use the InetAddress class in a Comparator .

A more efficient and accurate way to do it is with the InetAddress class mentioned above. Credits to 200_success for code.

import java.net.InetAddress; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Optional; import java.util.stream.Stream; public class IPSort < private static String[] TESTS = ; public static class InetAddressComparator implements Comparator < @Override public int compare(InetAddress a, InetAddress b) < byte[] aOctets = a.getAddress(), bOctets = b.getAddress(); int len = Math.max(aOctets.length, bOctets.length); for (int i = 0; i < len; i++) < byte aOctet = (i >= len - aOctets.length) ? aOctets[i - (len - aOctets.length)] : 0; byte bOctet = (i >= len - bOctets.length) ? bOctets[i - (len - bOctets.length)] : 0; if (aOctet != bOctet) return (0xff & aOctet) - (0xff & bOctet); > return 0; > > public static Optional toInetAddress(String s) < try < return Optional.of(InetAddress.getByName(s)); >catch (UnknownHostException badAddress) < return Optional.empty(); >> public static void main(String[] args) throws Exception < System.out.println("Valid 32-bit addresses"); Arrays.stream(TESTS) .map(IPSort::toInetAddress) .filter(Optional::isPresent) .map(Optional::get) .filter((addr) ->addr instanceof Inet4Address) .map(InetAddress::getHostAddress) .forEach(System.out::println); System.out.println("\nValid 128-bit addresses"); Arrays.stream(TESTS) .map(IPSort::toInetAddress) .filter(Optional::isPresent) .map(Optional::get) .filter((addr) -> addr instanceof Inet6Address) .map(InetAddress::getHostAddress) .forEach(System.out::println); System.out.println("\nInvalid addresses"); Arrays.stream(TESTS) .filter((s) -> !toInetAddress(s).isPresent()) .forEach(System.out::println); System.out.println("\nSorted addresses"); Arrays.stream(TESTS) .map(IPSort::toInetAddress) .filter(Optional::isPresent) .map(Optional::get) .sorted(new InetAddressComparator()) .map(InetAddress::getHostAddress) .forEach(System.out::println); > > 

Original Answer

Читайте также:  To define array in javascript

In order to sort IPs you first need to know a bit about them. There are two types of IPs; 32 Bit and 128 Bit .

32 Bit

  • The 32 bit IP is split into 4 groups of numbers between 0 and 255 . These groups are seperated via a .
  • A single group, as shown above, is 8 bits of data. This is the reason the numbers in a group are limited between 0 and 255 .
  • For a 32 bit IP to be formatted correctly it should be int.int.int.int . Even if the int is a 0 it must be shown in the IP address. This is different to a 128 bit IP which may omit 0 s. For example ::5: which is the same as 0:0:5:0:0:0:0:0 .

128 Bit

  • The 128 bit IP is split into 8 groups of numbers between 0 and FFFF (which is equivalent to 65535 ). Unlike a 32 bit IPs group, these groups are separated buy a : .
  • A single group, as show above, is 16 bits of data. This is the reason the numbers in the groups are limited between 0 and FFFF .
  • To format a 128 bit IP properly there are several rules you have to follow. 0 s may be omitted from groups and if the remaining groups all are 0 then the groups may also be omitted. The groups have to be separated by a : . If you are omitting groups the last group which isn’t a 0 has to be followed by a : . These rules leave us with a format int:int:int:int:int:int:int:int . An example of 0 s and groups being omitted would be 58f. fff:2: . This is the same as 58f:0:0:fff:2:0:0:0 .

Once the IPs have been sorted into their respective groups they can be sorted. To sort an IP you need to use a method called weighting. This is because simply adding or multiplying different groups together wouldn’t work. For example take the these two IPs; 192.5.48.198 and 198.48.5.192 . If you add or multiply the values of the groups together you get the same answer. So there is no way to accurately compare them using addition and multiplication. If you use weighting you get something like this.

32 Bit Weighting

Value of IP = (Group one value * 256^4) + (Group two value * 256^3) + (Group three value * 256^2) + (Group four value * 256) 

128 Bit Weighting

Value of IP = (Group one value * 65536^8) + (Group two value * 65536^7) + (Group three value * 65536^6) + (Group four value * 65536^5) + (Group five value * 65536^4) + (Group six value * 65536^3) + (Group seven value * 65536^2) + (Group eight value * 65536) 

The Code in Java

As long as the IP is formatted reasonably correctly this code will separate the two kinds of IP and then sort them.

import java.util.*; import java.math.*; //For BigInteger import java.util.regex.*; import java.lang.*; public class IPSort < String[] tests = ; ArrayList bit32 = new ArrayList(); ArrayList bit128 = new ArrayList(); ArrayList cleanBit32 = new ArrayList(); ArrayList cleanBit128 = new ArrayList(); boolean myMatcher32Bit(String s) < Pattern patter32Bit = Pattern.compile("^(?=(?:[^.]*\\.)[^.]*$)(?=(?:[^:]*:)[^:]*$)(?=(?:[^a-zA-Z]*[^a-zA-Z])*$)"); Matcher matcher32Bit = patter32Bit.matcher(s); return matcher32Bit.find(); > boolean myMatcher128Bit(String s) < Pattern patter128Bit = Pattern.compile("^(?=(?:[^.]*\\.)[^.]*$)(?=(?:[^:]*:)[^:]*$)"); Matcher matcher128Bit = patter128Bit.matcher(s); return matcher128Bit.find(); > public void sortIntoRespectiveIPTypes() < for(String s: tests) < if(myMatcher32Bit(s)) < bit32.add(s); >else if(myMatcher128Bit(s)) < bit128.add(s); >> System.out.println("32 bit IPs"); for(String ip: bit32) < System.out.println(" "+ip); >System.out.println("\n128 bit IPs"); for(String ip: bit128) < System.out.println(" "+ip); >int count = 0; for(String ip: tests) < if(myMatcher32Bit(ip)==false && myMatcher128Bit(ip)==false) < count++; >> if(count != 0) < System.out.println("\nDidn't match an IP format"); for(String ip: tests) < if(myMatcher32Bit(ip)==false && myMatcher128Bit(ip)==false) < System.out.println(" "+ip); >> > > public void sort32BitIPs(ArrayList bit32, ArrayList newBit32) < ArrayListbigInt32Bit = new ArrayList(); for(String ip:bit32) < String[] tempArray = ip.split("\\."); int i=0; for(String s:tempArray) < if(s.equals("")) < tempArray[i]="0"; >i++; > bigInt32Bit.add(convert32Bit(tempArray)); > Collections.sort(bigInt32Bit); ArrayList fixFormat = new ArrayList(); for(String ip:bit32) < String[] fixArray = ip.split("\\."); int i=0; for(String s:fixArray) < if(s.equals("")) < fixArray[i]="0"; >i++; > StringBuilder strBuilder = new StringBuilder(); for(int i2 = 0; i2 < 4; i2++) < if(i2<3) < try < if(!fixArray[i2].equals("")) < strBuilder.append(fixArray[i2]+"."); >else < strBuilder.append("."); >> catch(Exception e) < strBuilder.append("0."); >> else < try < strBuilder.append(fixArray[i2]); >catch(Exception e) < strBuilder.append("0"); >> > String newString = strBuilder.toString(); fixFormat.add(newString); bit32=fixFormat; > for(BigInteger finalValue:bigInt32Bit) < for(String ip:bit32) < String[] tempArray = ip.split("\\."); int i=0; for(String s:tempArray) < if(s.equals("")) < tempArray[i]="0"; >i++; > if(finalValue.equals(convert32Bit(tempArray))) < if(!newBit32.contains(ip)) < String str = bit32.toString(); String findStr = ip; int lastIndex = 0; int count = 0; while(lastIndex != -1)< lastIndex = str.indexOf(findStr,lastIndex); if(lastIndex != -1)< count++; lastIndex += findStr.length(); >> for(int k = 0; k > > > > > BigInteger convert32Bit(String[] array) < int[] tempArray = new int[array.length]; ArrayListtempBigIntList = new ArrayList(); int i = 0; for(String s:array) < int power = 4-i; tempArray[i]= Integer.parseInt(s); String string = Integer.toString(tempArray[i]); BigInteger myBigInt = new BigInteger(string); BigInteger num2 = myBigInt.multiply(new BigInteger("256").pow(power)); tempBigIntList.add(num2); i++; >BigInteger bigInt32Bit = new BigInteger("0"); for(BigInteger bI:tempBigIntList) < bigInt32Bit = bigInt32Bit.add(bI); >return bigInt32Bit; > public void sort128BitIPs(ArrayList bit128,ArrayList newBit128) < ArrayListbigInt128Bit = new ArrayList(); for(String ip:bit128) < String[] tempArray = ip.split(":"); int i=0; for(String s:tempArray) < if(s.equals("")) < tempArray[i]="0"; >i++; > bigInt128Bit.add(convert128Bit(tempArray)); > Collections.sort(bigInt128Bit); for(BigInteger finalValue:bigInt128Bit) < for(String ip:bit128) < String[] tempArray = ip.split(":"); int i=0; for(String s:tempArray) < if(s.equals("")) < tempArray[i]="0"; >i++; > if(finalValue.equals(convert128Bit(tempArray))) < if(!newBit128.contains(ip)) < String str = bit128.toString(); String findStr = ip; int lastIndex = 0; int count = 0; while(lastIndex != -1)< lastIndex = str.indexOf(findStr,lastIndex); if(lastIndex != -1)< count++; lastIndex += findStr.length(); >> for(int k = 0; k > > > > > BigInteger convert128Bit(String[] array) < int[] tempArray = new int[array.length]; ArrayListtempBigIntList = new ArrayList(); int i = 0; for(String s:array) < int power = 8-i; tempArray[i]= Integer.parseInt(s,16); String string = Integer.toString(tempArray[i]); BigInteger myBigInt = new BigInteger(string); BigInteger num2 = myBigInt.multiply(new BigInteger("65536").pow(power)); tempBigIntList.add(num2); i++; >BigInteger bigInt128Bit = new BigInteger("0"); for(BigInteger bI:tempBigIntList) < bigInt128Bit = bigInt128Bit.add(bI); >return bigInt128Bit; > public void printInOrder(ArrayList bit32,ArrayList bit128) < System.out.println("\nSorted IPs"); System.out.println("Sorted 32 bit IPs - Ascending"); for(String ip: bit32) < System.out.println(" "+ip); >Collections.reverse(bit32); System.out.println("\nSorted 32 bit IPs - Descending"); for(String ip: bit32) < System.out.println(" "+ip); >System.out.println("\nSorted 128 bit IPs - Ascending"); for(String ip: bit128) < System.out.println(" "+ip); >Collections.reverse(bit128); System.out.println("\nSorted 128 bit IPs - Descending"); for(String ip: bit128) < System.out.println(" "+ip); >> public void run(ArrayList bit32,ArrayList bit128,ArrayList newBit32,ArrayList newBit128) < sortIntoRespectiveIPTypes(); sort32BitIPs(bit32,newBit32); sort128BitIPs(bit128,newBit128); printInOrder(newBit32,newBit128); >public static void main(String[] args) < IPSort ipS = new IPSort(); ipS.run(ipS.bit32,ipS.bit128,ipS.cleanBit32,ipS.cleanBit128); >> 

As a note it is possible to use this class to sort IPs but my code does not use it

This code also sorts the list into an ascending order, then into a descending order. This is printed out in the command console when the code is run

Источник

Java how to sort a list of IP Address

I want to sort a list of IP address in ascending order, what is the easiest way to achieve that? For example I have these IP Address in a List :

import java.util.ArrayList; import java.util.List; /** * * @author myu */ public class SortListProject < /** * @param args the command line arguments */ public static void main(String[] args) < List addressList = new ArrayList(); addressList.add("192.168.0.5"); addressList.add("192.168.0.1"); addressList.add("192.168.25.1"); addressList.add("192.168.10.21"); addressList.add("192.168.77.1"); System.out.println(addressList); >> 

why not simply use a comparator converting those 4 octets to 4 bytes, then to a single int (a

6 Answers 6

You are using raw-types. Please don’t do that. Next, you’ll need to parse the String representation to get int values from the four octets in the IP (or 192.168.100.1 will come before 192.168.2.1). You can pass a custom Comparator to Collections.sort . Assuming you are using Java 8+, they might look something like

List addressList = new ArrayList<>(Arrays.asList("192.168.0.5", // "192.168.0.1", "192.168.25.1", "192.168.10.21", "192.168.77.1")); Collections.sort(addressList, (a, b) -> < int[] aOct = Arrays.stream(a.split("\\.")).mapToInt(Integer::parseInt).toArray(); int[] bOct = Arrays.stream(b.split("\\.")).mapToInt(Integer::parseInt).toArray(); int r = 0; for (int i = 0; i < aOct.length && i < bOct.length; i++) < r = Integer.compare(aOct[i], bOct[i]); if (r != 0) < return r; >> return r; >); System.out.println(addressList); 

The call to String.split() compiles a new java.util.regex.Pattern every time. You should just keep a constant pattern object for doing these splits as an optimization.

You can sort with Collections.sort , for example:

List addressList = new ArrayList<>(); addressList.add("192.168.0.5"); addressList.add("192.168.0.1"); addressList.add("192.168.25.1"); addressList.add("192.168.10.21"); addressList.add("192.168.77.1"); Collections.sort(addressList, new Comparator() < @Override public int compare(String o1, String o2) < String[] ip1 = o1.split("\\."); String ipFormatted1 = String.format("%3s.%3s.%3s.%3s", ip1[0],ip1[1],ip1[2],ip1[3]); String[] ip2 = o2.split("\\."); String ipFormatted2 = String.format("%3s.%3s.%3s.%3s", ip2[0],ip2[1],ip2[2],ip2[3]); return ipFormatted1.compareTo(ipFormatted2); >>); System.out.println("sorted: " + addressList); 
sorted: [192.168.0.1, 192.168.0.5, 192.168.10.21, 192.168.25.1, 192.168.77.1] 

The proper way is to use a comparator and generics (as outlined by folks earlier). Note that there is a fallacy of accepting the input data as being absolutely according to what you expect. For example in the case of IPs: 127.0.0.1 and 127.0.0.01 are both accepted by the Java Socket APIs. But the sort that you write should take care of these considerations as well. Therefore I recommend you to use a sorting based on the bytes (octets) of the ip address.

There are a lot of examples doing that and I would not go into that. A simple search would lead you to one on this very website.

What I would do instead is to demonstrate the need to sort by octets:

byte[] ipAddr1 = new byte[] < x1, x2, (byte) 010, x4 >; byte[] ipAddr2 = new byte[] < x1, x2, 9, x4 >; InetAddress addr = InetAddress.getByAddress(ipAddr1); InetAddress addr = InetAddress.getByAddress(ipAddr2); 

Both of these are accepted by the Java Socket library without it reporting any errors. They both work but if you sort it without taking into consideration of the individual octets (do a string sort for example) then the result might not be what you expect. Try it out and see.

For example (if you follow a Collections.sort(list) approach): if you have: «192.160.010.1» and «192.160.9.1». You would see the former appear as less than the latter but that is not true. The reason is that this will do a sort based on strings. That has nothing to do with the structure of an IP address.

Источник

sort a list of ips in ascending order

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 ipComparator = Comparator .comparing(IP::getFirstPart) .thenComparing(IP::getSecondPart) .thenComparing(IP::getThirdPart) .thenComparing(IP::getFourthPart); 
Comparator ipComparator = Comparator .comparing(IP::getPart(0)) .thenComparing(IP::getPart(1)) .thenComparing(IP::getPart(2)) .thenComparing(IP::getPart(3)); 

An IP address is just a representation of a 32 bit integer. You can convert them to numbers for sorting.

2 Answers 2

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[])); > 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))); 
ips.forEach(ip->System.out.println(ip.getHostAddress())); 
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 

Источник

Оцените статью