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

时间:2011-07-01 07:40:50

标签: python sorting dictionary 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

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

8 个答案:

答案 0 :(得分:32)

您可以使用自定义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内置支持按字典顺序对元组进行排序。

更新:使用socket模块中的inet_aton()功能实际上可以更轻松地完成此操作:

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

答案 1 :(得分:12)

使用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提出了一个使用套接字模块的解决方案,所以为什么不使用它来进行从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])

答案 2 :(得分:3)

如果您的应用程序执行了很多操作,例如“在范围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'

答案 3 :(得分:2)

  

我有什么选择?

我想到的两个显而易见的是:

  1. 使用IP 预格式化字符串时,将其存储为您在问题中添加的链接。
  2. 执行订购时,
  3. 将排序功能传递给sorted()功能。
  4. 哪个最好取决于您必须处理的数据量(您会注意到方法#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似乎已经为这种方法提供了一个很好的解决方案! :)

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

答案 6 :(得分:1)

一种处理正确订单的干净方法是使用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)

答案 7 :(得分:0)

完全不使用字符串而是将每个八位位组转换为整数,然后将其传递到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比较也可能是有益的。