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

发布于 2024-11-18 04:05:28 字数 639 浏览 4 评论 0原文

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

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

我发现这个,但我不知道如何实现它在我的代码,或者如果有可能,因为我使用字典。我在这里有什么选择?

I have a piece of code that looks like this:

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)

and it kind of sorts IP's, but like this:

192.168.102.105
192.168.204.111
192.168.99.11

which is not good enough since it does not recognize that 99 is a smaller number than 102 or 204. I would like the output to be like this:

192.168.99.11
192.168.102.105
192.168.204.111

I found this, but I am not sure how to implement it in my code, or if it is even possible since I use dictionary. What are my options here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

场罚期间 2024-11-25 04:05:28

您可以使用自定义 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'< /code> 并将其转换为整数元组 (192, 168, 102, 105)。 Python 内置支持按字典顺序对元组进行排序。

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

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

You can use a custom key function to return a sortable representation of your strings:

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)

The split_ip() function takes an IP address string like '192.168.102.105' and turns it into a tuple of integers (192, 168, 102, 105). Python has built-in support to sort tuples lexicographically.

UPDATE: This can actually be done even easier using the inet_aton() function in the socket module:

import socket
items = sorted(ipCount.items(), key=lambda item: socket.inet_aton(item[0]))
始终不够 2024-11-25 04:05:28

使用排序的关键参数将您的 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])

Use the key parameter of sorted to convert your ip to an integer, for example:

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

EDIT:

Gryphius proposes a solution with the socket module, and so why not use it to make the conversion from ip to long as it is cleaner:

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])
面犯桃花 2024-11-25 04:05:28

处理正确顺序的一种简洁方法是使用 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)

A clean way of handling the right order is using Pythons ipaddress module. You can transform the Strings into IPv4Address representations and sort them afterwards. Here's a working example with list objects (Tested with 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)
梦里南柯 2024-11-25 04:05:28

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

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

Found a solution at https://www.lesinskis.com/python_sorting_IP_addresses.html
All you have to do is convert the string of ip in ipaddress

import ipaddress
sortedkey = sorted(list_of_ip_instring, key = ipaddress.IPv4Address)
对风讲故事 2024-11-25 04:05:28

在 python 3 中

使用如下:

import ipaddress

clientIp = sorted(clientIp, key=ipaddress.IPv4Address)

for ip in clientIp:
    print(ip)

当 IP 地址是无类域间路由 (CIDR) 时,使用:

import ipaddress

clientIp = sorted(clientIp, key=ipaddress.IPv4Network)

for ip in clientIp:
    print(ip)

in python 3

use like this:

import ipaddress

clientIp = sorted(clientIp, key=ipaddress.IPv4Address)

for ip in clientIp:
    print(ip)

and when IP addresses are Classless Inter-Domain Routing (CIDR) use:

import ipaddress

clientIp = sorted(clientIp, key=ipaddress.IPv4Network)

for ip in clientIp:
    print(ip)
年华零落成诗 2024-11-25 04:05:28

如果你的应用程序做了很多事情,比如“在范围 x 中查找 ip”、“按 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'

if your application does lots of things like "find ips in range x", "sort by ip" etc its often more convenient to store the numeric value of the ip internally and work with this one.

from socket import inet_aton,inet_ntoa
import struct

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

convert the number back into an ip using this function:

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'
云朵有点甜 2024-11-25 04:05:28

我有什么选择?

我想到的两个明显的问题是:

  1. 当您将字符串存储为问题中放入的链接时,使用 IP 预格式化字符串
  2. 执行排序时,将排序函数传递给 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

排序函数示例

嗯...Ferdinand Beyer 在 <一个href="https://stackoverflow.com/questions/6545023/how-to-sort-ip-addresses-stored-in-dictionary-in-python/6545090#6545090">他的答案似乎已经为这种方法提供了一个很好的解决方案! :)

What are my options here?

The two obvious one that come to my mind are:

  1. Preformatting the strings with the IP when you store them as from the link you put in your question.
  2. Pass a sorting function to sorted() function when you perform the ordering.

Which is best depends from the amount of data you have to process (you will notice an increased performance for method #1 only for very large amount of data) and from what you will need to do with said sorted list of IP (if you preformat the strings, you might then need to change them again before feeding them as arguments to other functions, for example).

Example of preformatting

Maintain the IP as a string, but uses spaces or zeroes to solve the variable number of digits problem:

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

Example of sorting function

Well... Ferdinand Beyer in his answer seems to have already offered an excellent solution for this approach! :)

旧瑾黎汐 2024-11-25 04:05:28

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

I think this will help you: PEP265 (sorting dictionieries by value). Just extend the sorted function.

灯下孤影 2024-11-25 04:05:28

如果要对 IPv4/6 地址字符串列表进行排序,至少对于 python3 来说,正确且最简单的解决方案是转换为 ipaddress 对象并使用 ipaddress.get_mixed_type_key

import ipaddress

unsorted_ips = [
    "1.1.1.1",
    "1.0.0.1",
    "2606:4700:4700::1111",
    "2606:4700:4700::1001",
]

sorted_ips = sorted(
    [ipaddress.ip_address(ip) for ip in unsorted_ips], key=ipaddress.get_mixed_type_key
)

print(sorted_ips)

If you want to sort a list of IPv4/6 address strings, the correct and simplest solution, for python3 at least, is to convert to ipaddress objects and sort with ipaddress.get_mixed_type_key.

import ipaddress

unsorted_ips = [
    "1.1.1.1",
    "1.0.0.1",
    "2606:4700:4700::1111",
    "2606:4700:4700::1001",
]

sorted_ips = sorted(
    [ipaddress.ip_address(ip) for ip in unsorted_ips], key=ipaddress.get_mixed_type_key
)

print(sorted_ips)
甜宝宝 2024-11-25 04:05:28

完全不使用字符串,而是将每个八位字节转换为整数,然后将其传递到 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 进行比较可能会有所帮助。

how about not working with strings at all and instead convert each octet into integer, then passing it into 4 dimensional dictionary?

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

then it is easy to just sort an array by key, isnt it?

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)

for speed reasons it may be beneficial to also compare simple python dictionary against OrderedDict .

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文