如何在 Python 中对存储在字典中的 IP 地址进行排序?

Posted

技术标签:

【中文标题】如何在 Python 中对存储在字典中的 IP 地址进行排序?【英文标题】:How to sort IP addresses stored in dictionary in Python? 【发布时间】:2011-09-26 13:33:45 【问题描述】:

我有一段代码如下所示:

ipCount = defaultdict(int)

for logLine in logLines:
    date, serverIp, clientIp = logLine.split(" ")
    ipCount[clientIp] += 1

for clientIp, hitCount in sorted(ipCount.items), key=operator.itemgetter(0)):
    print(clientIp)

它对 IP 进行排序,但像这样:

192.168.102.105
192.168.204.111
192.168.99.11

这还不够好,因为它无法识别 99 是小于 102 或 204 的数字。我希望输出是这样的:

192.168.99.11
192.168.102.105
192.168.204.111

我找到了this,但我不确定如何在我的代码中实现它,或者因为我使用字典是否有可能。我在这里有什么选择?谢谢。。

【问题讨论】:

【参考方案1】:

您可以使用自定义 key 函数返回字符串的可排序表示:

def split_ip(ip):
    """Split a IP address given as string into a 4-tuple of integers."""
    return tuple(int(part) for part in ip.split('.'))

def my_key(item):
    return split_ip(item[0])

items = sorted(ipCount.items(), key=my_key)

split_ip() 函数接受一个 IP 地址字符串,如'192.168.102.105',并将其转换为整数元组(192, 168, 102, 105)。 Python 内置支持按字典顺序对元组进行排序。

更新:这实际上可以使用socket 模块中的inet_aton() 函数更轻松地完成:

import socket
items = sorted(ipCount.items(), key=lambda item: socket.inet_aton(item[0]))

【讨论】:

您也可以使用map 函数:sorted(ipCount.items(), key=lambda x:tuple(map(int, x.split('.'))))) 我看到使用 inet_aton 的更新答案不同:Ludo 调用 struct.unpack 而 Ferdinand 没有。这个函数调用是否需要订购? @randomtoor:没有必要。 inet_aton 返回一个 4 个字符的字符串,Python 知道如何对字符串进行比较和排序。 更新版太棒了!应该是主要版本并回答 IMO。【参考方案2】:

使用 sorted 的 key 参数将你的 ip 转换为整数,例如:

list_of_ips = ['192.168.204.111', '192.168.99.11', '192.168.102.105']
sorted(list_of_ips, key=lambda ip: long(''.join(["%02X" % long(i) for i in ip.split('.')]), 16))

编辑:

Gryphius 提出了一个带有 socket 模块的解决方案,所以为什么不使用它来进行从 ip 到 long 的转换,因为它更干净:

from socket import inet_aton
import struct
list_of_ips = ['192.168.204.111', '192.168.99.11', '192.168.102.105']
sorted(list_of_ips, key=lambda ip: struct.unpack("!L", inet_aton(ip))[0])

【讨论】:

我想给这个+1,但它需要一点解释。具体来说,为什么[0]【参考方案3】:

处理正确订单的一种简洁方法是使用 Pythons ipaddress 模块。您可以将字符串转换为 IPv4Address 表示形式,然后对其进行排序。这是一个带有列表对象的工作示例(使用 Python3 测试):

import ipaddress

unsorted_list = [
  '192.168.102.105',
  '192.168.204.111',
  '192.168.99.11'
]

new_list = []

for element in unsorted_list:
  new_list.append(ipaddress.ip_address(element))

new_list.sort()

# [IPv4Address('192.168.99.11'), IPv4Address('192.168.102.105'), IPv4Address('192.168.204.111')]
print(new_list)

【讨论】:

【参考方案4】:

在https://www.lesinskis.com/python_sorting_IP_addresses.html 找到了解决方案 你所要做的就是转换ipaddress中的ip字符串

import ipaddress
sortedkey = sorted(list_of_ip_instring, key = ipaddress.IPv4Address)

【讨论】:

【参考方案5】:

如果您的应用程序做了很多事情,例如“在 x 范围内查找 ips”、“按 ip 排序”等,那么在内部存储 ip 的数值并使用它通常会更方便。

from socket import inet_aton,inet_ntoa
import struct

def ip2long(ip):
    packed = inet_aton(ip)
    lng = struct.unpack("!L", packed)[0]
    return lng

使用此函数将数字转换回 ip:

def long2ip(lng):
    packed = struct.pack("!L", lng)
    ip=inet_ntoa(packed)
    return ip


>>> ip2long('192.168.1.1')
3232235777
>>> ip2long('1.2.3.4')
16909060
>>> long2ip(3232235777)
'192.168.1.1'
>>> long2ip(16909060)
'1.2.3.4'

【讨论】:

+1 用于推荐 socket 模块。但由于问题是关于排序的,你可能想举一个例子来说明如何在这种情况下使用它。【参考方案6】:

我有什么选择?

我想到的两个明显的是:

    使用 IP 对字符串进行预格式化,当您将字符串存储为您在问题中输入的链接时。 在执行排序时将排序函数传递给sorted() 函数。

哪个最好取决于您必须处理的数据量(您会注意到方法 #1 仅在处理大量数据时性能有所提高)以及您需要做什么使用所述排序的 IP 列表(例如,如果您预先格式化字符串,则可能需要再次更改它们,然后再将它们作为参数提供给其他函数)。

预格式化示例

将IP保持为字符串,但使用空格或零来解决可变位数问题:

>>> ip = '192.168.1.1'
>>> print('%3s.%3s.%3s.%3s' % tuple(ip.split('.')))
192.168.  1.  1
>>> print('%s.%s.%s.%s' % tuple([s.zfill(3) for s in ip.split('.')]))
192.168.001.001

排序函数示例

嗯...his answer 中的 Ferdinand Beyer 似乎已经为这种方法提供了一个很好的解决方案! :)

【讨论】:

【参考方案7】:

我认为这会对您有所帮助:PEP265(按值对字典进行排序)。只需扩展 sorted 函数即可。

【讨论】:

【参考方案8】:

完全不使用字符串,而是将每个八位字节转换为整数,然后将其传递到 4 维字典中怎么样?

ClientIps[192][168][102][105]=1
ClientIps[192][168][99][11]=1

那么通过键对数组进行排序很容易,不是吗?

for key1, value in sorted(ClientIps.items()): 
  for key2, value in sorted(ClientIps[key1].items()): 
    for key3, value in sorted(ClientIps[key1][key2].items()): 
      for key4, value in sorted(ClientIps[key][key2][key3].items()): 
        print(key1, key2, key3, key4)

出于速度原因,将简单的 python 字典与 OrderedDict 进行比较可能会有所帮助。

【讨论】:

以上是关于如何在 Python 中对存储在字典中的 IP 地址进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中对字典使用 reduce

如何在 Python 中对字典列表进行多重排序? [复制]

如何在 Python 中对大量字典进行排序而不加载到内存中

在Python列表中对嵌套字典进行排序? [复制]

python中对文件的处理

如何在 AngularJs 中对字典使用 ng-repeat?