如何在Python字典中对IP地址进行排序?
我有一段代码,看起来是这样的:
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
我找到了这个链接,但我不太确定怎么把它用到我的代码里,或者说这样做是否可行,因为我使用的是字典。请问我有哪些选择呢?
10 个回答
10
处理正确顺序的一种简单方法是使用Python的 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)
15
使用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地址转换成长整型呢,这样会更简洁:
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])
48
你可以使用一个自定义的 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()
函数可以把像 '192.168.102.105'
这样的IP地址字符串转换成一个整数元组 (192, 168, 102, 105)
。Python内置支持按字典顺序对元组进行排序。
更新:其实可以更简单地使用 inet_aton()
函数,这个函数在 socket
模块里:
import socket
items = sorted(ipCount.items(), key=lambda item: socket.inet_aton(item[0]))