How to sort IP addresses stored in dictionary in Python?

Solution 1:

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

Solution 2:

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

Solution 3:

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)

Solution 4:

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)

Solution 5:

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'