【问题标题】:Sort on the last octet of an IP address in a Python list按 Python 列表中 IP 地址的最后一个八位字节排序
【发布时间】:2016-04-07 02:40:38
【问题描述】:

这有点令人难以置信(至少对我而言)。我正在使用一个简单的 Python 脚本来返回一个使用 fping 的“up”主机列表。我将每个“up”主机存储在 Python 列表中,但是 list.sort() 显然不会根据存储为字符串的 IP 地址的最后一个八位字节进行排序。我想对 .1、.2、.3 等进行降序排序。

这是那部分代码:

for addr in os.popen("fping -a -q -g " + subnet):
    addr = addr.rstrip('\n')
    addr_list.append(addr)

addr_list.sort()
for ip in addr_list:
    print ip

【问题讨论】:

  • 给我们一个你的清单的例子。
  • addr_list 在.sort() 之前是什么样子的?
  • octet?你说的是数字吗?
  • @Reblochon - IP 地址中的四个数字中的每一个都称为八位字节,因为它由 8 位表示。例如IP地址192.168.1.101中,第一个八位字节为192,第二个八位字节为168,以此类推
  • 你到底为什么想要按最后一个八位字节排序?不是说这种有用的情况不存在......它真的很奇怪。

标签: python networking ip


【解决方案1】:

对于最后一个八位字节,您可以在密钥中使用rsplit():

addr_list = [  # Thanks @aneroid
    '10.11.12.13',
    '1.2.3.4',
    '127.0.0.1',
    '192.168.0.1',
]

>>> sorted(addr_list, key=lambda x: int(x.rsplit('.', 1)[1]), reverse=True)
['10.11.12.13', '1.2.3.4', '127.0.0.1', '192.168.0.1']

这是下降的 - 但你的例子似乎是上升的:

>>> sorted(addr_list, key=lambda x: int(x.rsplit('.', 1)[1]))
['127.0.0.1', '192.168.0.1', '1.2.3.4', '10.11.12.13']

但我想我更喜欢@aneroid 的元组排序:

>>> sorted(addr_list, key=lambda x: tuple(map(int, reversed(x.split('.')))))
['127.0.0.1', '192.168.0.1', '1.2.3.4', '10.11.12.13']

【讨论】:

    【解决方案2】:

    假设您的 addr_list 列表如下所示(您尚未在问题中指定它):

    addr_list = [
        '10.11.12.13',
        '1.2.3.4',
        '127.0.0.1',
        '192.168.0.1',
    ]
    

    拆分. 并使用最后一项(最后一个八位字节)作为排序的关键。当然,对于 '127.0.0.1' 和 '192.168.0.1',您可能希望对倒数第二个八位字节、倒数第三个八位字节和第一个八位字节进行排序。

    所以将此行为用作key:

    >>> list(reversed('10.11.12.13'.split('.')))
    ['13', '12', '11', '10']
    >>> sorted(addr_list, key=lambda ip: list(reversed(ip.split('.'))))
    ['127.0.0.1', '192.168.0.1', '10.11.12.13', '1.2.3.4']
    

    请注意,13 在 4 之前列出。所以还要确保它将每个项目作为一个数字而不是一个字符串进行比较:

    >>> sorted(addr_list, key=lambda ip: map(int, reversed(ip.split('.'))))
    ['127.0.0.1', '192.168.0.1', '1.2.3.4', '10.11.12.13']
    

    要么将其分配给另一个列表,要么进行就地排序:

    >>> addr_list.sort(key=lambda ip: map(int, reversed(ip.split('.'))))
    >>> addr_list
    ['127.0.0.1', '192.168.0.1', '1.2.3.4', '10.11.12.13']
    

    【讨论】:

    • 您需要在此处某处强制转换为 int,否则,它们将按字典顺序排序而不是按数字排序,如您的最后一个示例所示(.13 在 .4 之前,但应该是相反的) .
    【解决方案3】:

    sort 可以将函数用于执行比较的参数作为参数。该函数接受两个输入,如果第一个参数被认为更大,则返回1,如果第二个参数更大,则返回-1,如果它们相等则返回0,以便进行排序。这是适合您的情况的功能:

    def compare_ips(ip1, ip2):
        last_octet1 = int(ip1.split('.')[-1]) # splits the ip and grabs the last octet
        last_octet2 = int(ip2.split('.')[-1]) # splits the ip and grabs the last octet
        if last_octet1 > last_octet2:
            return 1
        if last_octet1 < last_octet2:
            return -1
        return 0
    

    然后您只需将其作为关键字参数提供给排序:

    >>> ips = ['192.168.1.101', '251.39.0.103', '127.0.0.1']
    >>> ips.sort(cmp = compare_ips)
    >>> ips
    ['127.0.0.1', '192.168.1.101', '251.39.0.103']
    

    【讨论】:

    • cmp 总是比key 慢,因为它需要为列表中的每个条目“转换”两个参数。它确实适用于更复杂的对象,其中排序不如简单转换为整数来实现。
    • @Brian 感谢您的提示!我没有意识到这一点。
    • 这个也很棒——非常高效。多谢了。
    • 我很高兴它有帮助!没问题!
    【解决方案4】:

    仅按最后一个八位位组排序是一个非常奇怪的要求,因为较高的八位位组通常会告诉您更多有关地址的信息(例如,公共可路由地址的来源国家/地区,小型网络的子网)。

    更一般地说,这将按数字表示对 IP 地址列表进行排序:

    import socket
    ip_list = ['192.168.1.120', '192.168.1.30',  '127.0.0.1']
    
    # numeric sort, leveraging inet_pton to convert valid IPv4 address
    # notation to a 'packed' string of 4 bytes, which will then sort correctly.
    print sorted(ip_list, key=lambda (x): socket.inet_pton(socket.AF_INET, x))
    
    # strict string-based sort for comparison
    print sorted(ip_list)
    

    或者,如果您不想将 socket 模块用于 inet_pton:

    def ip2int(ipstr):
        octets = [int(x) for x in ipstr.split('.')]
        return sum( (o << (8 * 3-i) for i,o in enumerate(octets)) )
    sorted(ip_list, key=ip2int)
    

    【讨论】:

    • 同意——通常这会很奇怪,但我们只是对我们网络上的主机有一个粗略的了解。我们在 32 个子网中有大约 401 个。这太疯狂了(最后一个管理员是一只奇怪的鸭子)。
    【解决方案5】:
    addr_list = [
        '10.11.12.3',
        '1.2.3.4',
        '127.0.0.1',
        '192.168.0.2',
    ]
    
    # lambda x=192.168.0.2 , ip.split= ['192','168','0','2'][-1] = 2
    sorted_ips = sorted(addr_list , key=lambda ip: ip.split('.')[-1])
    for ip in sorted_ips:
      print(ip)
    

    【讨论】:

      猜你喜欢
      • 2014-05-13
      • 1970-01-01
      • 1970-01-01
      • 2019-01-02
      • 2018-09-19
      • 1970-01-01
      • 1970-01-01
      • 2021-08-26
      • 2020-08-04
      相关资源
      最近更新 更多