Python: сортировка диапазонов ip, которые являются ключами словаря - PullRequest
0 голосов
/ 20 июня 2019

У меня есть словарь, который имеет диапазоны IP-адресов в виде ключей (используется для дедупликации на предыдущем шаге) и определенные объекты в качестве значений.Вот пример

Часть словаря sresult:

10.102.152.64-10.102.152.95 object1:object3
10.102.158.0-10.102.158.255 object2:object5:object4
10.102.158.0-10.102.158.31  object3:object4
10.102.159.0-10.102.255.255 object6

Есть десятки тысяч строк, которые я хочу (правильно) отсортировать по IP-адресу в ключах

Я попытался разделить ключ на основе разделителя диапазона -, чтобы получить один IP-адрес, который можно отсортировать следующим образом:

ips={}
for key in sresult:
    if '-' in key:
        l = key.split('-')[0]
        ips[l] = key
    else:
        ips[1] = key

А затем с помощью кода, найденного в другом сообщении, отсортировать по IP-адресуи затем поиск значений в исходном словаре:

sips = sorted(ipaddress.ip_address(line.strip()) for line in ips)
for x in sips:
    print("SRC: "+ips[str(x)], "OBJECT: "+" :".join(list(set(sresult[ips[str(x)]]))), sep=",")

Проблема, с которой я столкнулся, заключается в том, что когда я разделяю исходный диапазон и добавляю отсортированные первые IP-адреса в качестве новых ключей в другом словаре, я дублируюснова теряем строки данных - строки 2 и 3 в примере

 line 1 10.102.152.64 -10.102.152.95
 line 2 10.102.158.0  -10.102.158.255
 line 3 10.102.158.0  -10.102.158.31
 line 4 10.102.159.0  -10.102.255.25

становятся

line 1 10.102.152.64 -10.102.152.95
line 3 10.102.158.0  -10.102.158.31
line 4 10.102.159.0  -10.102.255.25

Таким образом, при восстановлении исходного словаря с использованием отсортированных по IP-адресу ключей я потерял данные

Может кто-нибудь помочь, пожалуйста?

1 Ответ

0 голосов
/ 20 июня 2019

РЕДАКТИРОВАТЬ Эта запись теперь состоит из трех частей:

1) Немного информации о словарях, которая понадобится вам для понимания всего остального. 2) Анализ вашего кода, и как вы можете это исправить, не используя какие-либо другие функции Python. 3) Что бы я посчитал лучшим решением проблемы, подробно.

1) Словари

Словари Python не упорядочены. Если у меня есть словарь, как это:

dictionary = {"one": 1, "two": 2}

И я перебираю словарь dictionary.items (), я мог получить «один»: 1 первым, или я мог получить «два»: 2 первым. Я не знаю.

Каждый словарь Python неявно имеет два списка, связанных с ним: список его ключей и список его значений. Вы можете получить их перечислить это:

print(list(dictionary.keys()))
print(list(dictionary.values()))

Эти списки имеют порядок. Таким образом, они могут быть отсортированы. Конечно, это не изменит исходный словарь.

Ваш код

Что вы поняли, так это то, что в вашем случае вы хотите сортировать только по первому IP-адресу в ключах ваших словарей. Поэтому стратегия, которую вы приняли, выглядит примерно так:

1) Создайте новый словарь, где ключами являются только эта первая часть. 2) Получить этот список ключей из словаря. 3) Сортировать этот список ключей. 4) Запросить исходный словарь для значений.

Этот подход, как вы заметили, потерпит неудачу на шаге 1. Потому что, как только вы создадите новый словарь с усеченными ключами, вы потеряете способность различать некоторые ключи, которые в конце были различны. Каждый ключ словаря должен быть уникальным.

Лучшая стратегия была бы:

1) Создайте функцию, которая может представлять ваши «полные» IP-адреса в качестве объекта ip_address.

2) Сортировать список ключей словаря (оригинальный словарь, не создавайте новый).

3) Запросить словарь по порядку.

Давайте посмотрим, как мы могли бы изменить ваш код для реализации шага 1.

def represent(full_ip):
    if '-' in full_ip:
        # Stylistic note, never use o or l as variable names.
        # They look just like 0 and 1.
        first_part = full_ip.split('-')[0]
        return ipaddress.ip_address(first_part.strip())

Теперь, когда у нас есть способ представления полных IP-адресов, мы можем отсортировать их в соответствии с этой сокращенной версией, без необходимости вообще менять ключи. Все, что нам нужно сделать, это сообщить отсортированному методу Python, как мы хотим, чтобы ключ был представлен, используя параметр ключа (NB, этот параметр ключа не имеет ничего общего с ключом в словаре. Просто они оба были названы ключом.):

# Another stylistic note, always use .keys() when looping over dictionary keys. Explicit is better than implicit.

sips = sorted(sresults.keys(), key=represent)

И если эта библиотека ipaddress работает, проблем здесь быть не должно. Оставшуюся часть кода вы можете использовать как есть.

Часть 3 Лучшее решение

Когда бы вы ни занимались сортировкой чего-либо, всегда легче думать о гораздо более простой проблеме: учитывая два элемента, как бы я их сравнил? Python дает нам способ сделать это. Нам нужно реализовать два метода модели данных, которые называются

__le__

и

__eq__

Давайте попробуем сделать это:

class IPAddress:
    def __init__(self, ip_address):
        self.ip_address = ip_address # This will be the full IP address

    def __le__(self, other):
        """ Is this object less than or equal to the other one?"""
        # First, let's find the first parts of the ip addresses
        this_first_ip = self.ip_address.split("-")[0]
        other_first_ip = other.ip_address.split("-")[0]
        # Now let's put them into the external library
        this_object = ipaddress.ip_address(this_first_ip)
        other_object = ipaddress.ip_adress(other_first_ip)
        return this_object <= other_object

    def __eq__(self, other):
        """Are the two objects equal?"""
        return self.ip_address == other.ip_adress

Круто, у нас есть класс. Теперь методы модели данных будут автоматически вызываться каждый раз, когда я использую «<» или «<=» или «==». Давайте проверим, что это работает: </p>

test_ip_1 = IPAddress("10.102.152.64-10.102.152.95")
test_ip_2 = IPAddress("10.102.158.0-10.102.158.255")

print(test_ip_1 <= test_ip_2)

Теперь, прелесть этих методов модели данных в том, что Питоны "сортируют" и "сортируют" также будут использовать их:

dictionary_keys = sresult.keys()
dictionary_key_objects = [IPAddress(key) for key in dictionary_keys]
sorted_dictionary_key_objects = sorted(dictionary_key_objects)
# According to you latest comment, the line below is what you are missing
sorted_dictionary_keys = [object.ip_address for object in sorted_dictionary_key_objects]

А теперь вы можете сделать:

for key in sorted_dictionary_keys:
    print(key)
    print(sresults[key])

Модель данных Python является почти определяющей особенностью Python. Я бы порекомендовал прочитать об этом.

...