按升序对 ips 列表进行排序

sort a list of ips in ascending order

我有一个 ip 对象列表,它们的 v4 地址是一个字符串。 (ip为十进制)

现在我想以 ip 部分作为搜索关键字对这个列表进行升序排序。

这是我的第一个方法。它可以工作,但它需要四个函数来 return ip 的每个部分。

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

我想做这样的事情

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

在不为 return ip 的每个部分定义函数的情况下,最简单的实现方法是什么?

如果您将它们表示为像“192.168.2.4”这样的自然字符串,那么它们将无法排序,但是如果您 zero-prefix 每个八位字节都像“192.168.002.004”,那么这些字符串将被排序正如预期的那样。同样,您可以用十六进制表示它们,例如“C0A80204”。密钥是每个八位字节的固定宽度。

或者,您可以将 4 个八位字节表示为一个数字。需要注意的是,如果第一个八位字节是127或更高,那么一个32位的整数会把它当作一个负数,这会影响排序顺序。最简单的解决方案(如果不是最 memory-efficient)是 return 它作为一个 long 值。

这是一种方法。

  • 创建一个列表来保存 IP 地址。
List<InetAddress> ips = new ArrayList<>();

然后创建一些进行排序。我正在演示 Inet4Address class 以接受点分四边形或字节数组。然后洗牌。

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);

根据源代码,Inet4AddresshashCode 是地址本身。这可以在不使用密钥提取器的情况下用于排序。但据我所知,它没有记录在案,因此不应依赖。所以可以这样做:

  • 使用 ByteBuffer 包装从 getAddress() 返回的字节数组并检索 int 值。
  • 然后。由于高位可以任意出现在 IP 地址中,因此对排序
  • 应用的两个 ip 进行无符号比较
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