2011-07-01 23 views
10

Tôi có một đoạn mã mà trông như thế này:Làm thế nào để sắp xếp địa chỉ IP được lưu trữ trong từ điển bằng Python?

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) 

và nó loại phân loại IP, nhưng như thế này:

192.168.102.105 
192.168.204.111 
192.168.99.11 

đó là không đủ tốt vì nó không nhận ra rằng 99 là một số nhỏ hơn 102 hoặc 204. Tôi muốn đầu ra giống như thế này:

192.168.99.11 
192.168.102.105 
192.168.204.111 

Tôi tìm thấy this, nhưng tôi không chắc chắn cách cấy ement nó trong mã của tôi, hoặc nếu nó thậm chí có thể kể từ khi tôi sử dụng từ điển. lựa chọn của tôi là gì đây? Cảm ơn bạn ..

Trả lời

24

bạn có thể sử dụng một tùy chỉnh key hàm trả về một đại diện có thể phân loại các chuỗi của bạn:

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) 

Các split_ip() chức năng phải mất một chuỗi địa chỉ IP như '192.168.102.105' và biến nó thành một tuple của số nguyên (192, 168, 102, 105). Python đã tích hợp sẵn hỗ trợ để sắp xếp các bộ dữ liệu theo từ điển.

CẬP NHẬT: Đây thực sự có thể được thực hiện dễ dàng hơn bằng cách sử dụng chức năng inet_aton() trong module socket:

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

Bạn cũng có thể làm điều này với các chức năng 'map': 'sắp xếp (ipCount.items(), key = lambda x: tuple (map (int, x.split ('.'))))) ' – Handyman5

+0

Tôi thấy các câu trả lời được cập nhật bằng cách sử dụng inet_aton là khác nhau: lệnh gọi struct.unpack của Ludo và của Ferdinand thì không. Chức năng này có cần phải gọi để đặt hàng hay không? –

+0

@randomtoor: Đó là * không * cần thiết. 'inet_aton' trả về một chuỗi gồm 4 ký tự và Python biết cách so sánh và sắp xếp các chuỗi. –

2

Tùy chọn của tôi ở đây là gì?

Hai một rõ ràng mà tôi suy nghĩ của tôi là:

  1. Preformatting các dây với IP khi bạn lưu trữ chúng như từ liên kết mà bạn đưa vào câu hỏi của bạn.
  2. Chuyển chức năng sắp xếp đến sorted() hoạt động khi bạn thực hiện yêu cầu.

nào là tốt nhất phụ thuộc vào số dữ liệu bạn phải xử lý (bạn sẽ nhận thấy một hiệu suất tăng lên đối với phương pháp # 1 chỉ dành cho số lượng rất lớn dữ liệu) và từ những gì bạn sẽ cần phải làm gì với nói danh sách IP được sắp xếp (nếu bạn định dạng trước các chuỗi, sau đó bạn có thể cần phải thay đổi chúng một lần nữa trước khi cho chúng làm đối số cho các hàm khác, ví dụ).

Ví dụ về preformatting

Duy trì IP như là một chuỗi, nhưng sử dụng không gian hoặc zero để giải quyết số lượng biến của vấn đề chữ số:

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

Ví dụ về chức năng

sắp xếp

Vâng ... Ferdinand Beyer trong his answer dường như đã cung cấp một giải pháp tuyệt vời cho phương pháp này!:)

10

Sử dụng các thông số quan trọng của sắp xếp để chuyển đổi ip của bạn thành một số nguyên, ví dụ:

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 đề xuất một giải pháp với các mô-đun ổ cắm, và vậy tại sao không sử dụng nó làm cho việc chuyển đổi từ ip để lâu vì nó là sạch hơn:

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

Tôi nghĩ rằng đây sẽ giúp bạn: PEP265 (sắp xếp dictionieries theo giá trị). Chỉ cần mở rộng hàm được sắp xếp.

2

nếu ứng dụng của bạn thực hiện rất nhiều thứ như "tìm ips trong phạm vi x", "sắp xếp theo ip" vv thường thuận tiện hơn để lưu trữ giá trị số của ip nội bộ và làm việc với cái này.

from socket import inet_aton,inet_ntoa 
import struct 

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

chuyển đổi số lại thành một ip sử dụng chức năng này:

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' 
+0

+1 để giới thiệu mô đun 'socket'. Nhưng vì câu hỏi là sắp xếp, bạn có thể muốn đưa ra một ví dụ về cách sử dụng nó trong ngữ cảnh này. –

+0

sixfeetsix vừa làm :-) – Gryphius

+0

Vâng, tôi cũng vậy;) –

Các vấn đề liên quan