【问题标题】:Given a list of IP address, how do you find min, max?给定一个 IP 地址列表,如何找到最小值、最大值?
【发布时间】:2011-02-18 00:45:51
【问题描述】:

在Java 中,我有一个IP 地址的arrayList。我如何找到最小值和最大值?

我已经使用了 Collection.min() 但它在以下情况下不起作用:

192.168.0.1  <--min 
192.168.0.250
192.168.0.9  <--max

我如何返回

192.168.0.1  <--min
192.168.0.250 <--max

相反?


ArrayList 是从数据库中检索的。我需要在每个滴答声中执行此操作(每个滴答声的间隔为 5 秒)。 IP 地址的数量最多可能达到 300 个。

【问题讨论】:

  • 这个排序的值是多少?你为什么在乎?

标签: java collections ip-address


【解决方案1】:

将IP地址转换成长整数,然后排序。 192.168.0.1 可以使用二进制算术/运算符转换为整数:

( 192 << 24 ) + ( 168 << 16 ) + ( 0 << 8 ) + ( 1 << 0 )

等等。请阅读下面关于使用正确数据类型的 cmets。

【讨论】:

  • 几乎:对于最高八位字节至少为 128 的 IP 地址,这将失败,因为结果 int 将为负数。请改用long。他也可能想要原始 IP,所以最好的办法是创建一个从 long IP 值到 String 表示的 TreeMap。按顺序迭代会按顺序给出 IP 地址。
  • 我不是Java专家,所以我建议你使用正确的数据类型。我相信Java整数是8个字节,如果是这样,那么上面的计算就可以了。
  • 没有 Java int 是 32 位有符号值。 Java long 是一个 64 位(8 字节)签名的,并且在 Sean 状态下是必需的。
  • @sean - 同意使用 long。我不同意使用字符串。我有一个子网计算器/计算器,很久以前我发现最好在需要时操纵长整数并重现字符串。在这种情况下,转换一个IP,它不会被注意到。在我的情况下,可能有数百万个地址,这很重要。
【解决方案2】:

您是否将 IP 地址存储为 String 实例?很可能是这种情况,因为String 是按字典顺序排序的,即"10" &lt; "2"

如果要对它们进行数字排序,有几种方法:

  • 不要将它们放入List&lt;String&gt;,而是将它们放入List&lt;Integer&gt;
    • 甚至可能是SortedSet&lt;Integer&gt;
  • 保留List&lt;String&gt;,但提供一个自定义比较器,将String 转换为数值以进行比较
    • 可能不是最有效的,但无需对现有基础架构进行重大更改即可工作
      • 虽然也许从一开始就进行重大更改并不是一个坏主意...

这是一个将两者合二为一的示例:

import java.util.*;

public class IPSorter {
    static Long toNumeric(String ip) {
        Scanner sc = new Scanner(ip).useDelimiter("\\.");
        return 
            (sc.nextLong() << 24) + 
            (sc.nextLong() << 16) + 
            (sc.nextLong() << 8) + 
            (sc.nextLong()); 
    }
    public static void main(String[] args) {
        Comparator<String> ipComparator = new Comparator<String>() {
            @Override public int compare(String ip1, String ip2) {
                return toNumeric(ip1).compareTo(toNumeric(ip2));
            }       
        };
        SortedSet<String> ips = new TreeSet<String>(ipComparator);
        ips.addAll(Arrays.asList(
            "192.168.0.1", "192.168.0.250", "192.168.0.9", "9.9.9.9"
        ));
        System.out.println(ips);
        // "[9.9.9.9, 192.168.0.1, 192.168.0.9, 192.168.0.250]"
    }
}

API 链接

【讨论】:

    【解决方案3】:

    如果您将 IP 地址视为整数(长整数),则可以对其进行排序。编写一个自定义比较器,可以将 IP 地址拆分为一个 int 数组,然后通过执行以下操作创建一个总 int 值。

    //Split and convert the address into an array of ints...
    
    addressIntValue =  address[0] * 256 * 256 * 256
    addressIntValue += address[1] * 256 * 256
    addressIntValue += address[2] * 256
    addressIntValue += address[3]
    

    然后您可以按“addressIntValue”排序。

    【讨论】:

    • 如果你只乘以 255,“0.0.0.255”和“0.0.1.0”的值是相同的 -> 你必须乘以 2^8 = 256(更好:使用位移, a*2^b = a 见 Salman 的回答,加上 Sean Owen 的补充(长而不是 int)
    【解决方案4】:

    如果不想手动解析IP,可以使用InetAddressclass

    InetAddress ia1 = InetAddress.getByName("192.168.0.9");
    InetAddress ia2 = InetAddress.getByName("192.168.0.234");
    
    System.out.println(ia1.hashCode() < ia2.hashCode());
    

    我正在使用hashCode() 方法,因为它将地址作为ipv4 的数字返回。您还可以比较 InetAddress.getAddress() 返回的数组

    编辑 使用hashCode() 是一项未记录的功能,如果您同时拥有 ipv6 和 ipv4 地址,则可能会出现问题。所以最好是比较字节数组或者手动转换成数字。

    【讨论】:

    • 如果不是因为它使用了InetAddress#hashCode() 的(未记录的)实现细节,我会更喜欢这种方法(事实上,如果不运行它,我什至无法判断这段代码是否正确, 或查看 InetAddress 的源代码,还有在未来版本中实现更改的担忧)。
    • @jack-leow 虽然 javadoc 没有明确提到地址也是 hashCode,但它是完全合理的,并且绝对 no 有理由期望它会改变在未来的版本中(更不用说 Java 传统上保持向后兼容性,几乎是错误的)。就其本质而言,地址是完美 hashCode 的定义。
    【解决方案5】:

    参考Java – IP Address to Integer and back

    public static String intToIp(int i) {
        return ((i >> 24 ) & 0xFF) + "." +
               ((i >> 16 ) & 0xFF) + "." +
               ((i >>  8 ) & 0xFF) + "." +
               ( i        & 0xFF);
    }
    
    public static Long ipToInt(String addr) {
        String[] addrArray = addr.split("\\.");
    
        long num = 0;
        for (int i=0;i<addrArray.length;i++) {
            int power = 3-i;
    
            num += ((Integer.parseInt(addrArray[i])%256 * Math.pow(256,power)));
        }
        return num;
    }
    

    从数据库中检索 IP 地址字符串,我将全部转换为 ArrayList,然后应用 Collection.min() 然后我将 long 转换回 int,然后再转换回 String。获取已排序的 IP 地址字符串。

    谢谢

    【讨论】:

      猜你喜欢
      • 2012-03-20
      • 1970-01-01
      • 2018-06-19
      • 2020-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2020-12-02
      相关资源
      最近更新 更多