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

26 投票
10 回答
41278 浏览
提问于 2025-04-16 20:38

我有一段代码,看起来是这样的:

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

撰写回答