Python: сортировка диапазонов IP-адресов, которые являются ключами словаря

У меня есть словарь, который имеет диапазоны 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-адресов я потерял данные.

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

Не могли бы вы предоставить желаемый результат?

UdonN00dle 20.06.2019 15:10

Желаемый результат совпадает с исходными данными, отсортированными по первому IP-адресу в диапазонах. Как оказалось, пример, который я привел, был именно в таком порядке, но при использовании этого порядка 10.90.0.0-10.90.255.255 он будет последним, тогда как на самом деле 10.96 < 10.102 он должен стоять первым.

hairless1 21.06.2019 07:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
654
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

1) Словари

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

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

И я перебираю словарь.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 sorted, как мы хотим, чтобы ключ был представлен, используя ключевой параметр (обратите внимание, этот ключевой параметр не имеет ничего общего с ключом в словаре. Просто они оба называются ключами):

# 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

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

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)

Теперь красота этих методов модели данных заключается в том, что Python «sort» и «sorted» также будет использовать их:

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. Я бы порекомендовал прочитать об этом.

Спасибо за ответ. Я не могу честно сказать, что понимаю, но я попытаюсь понять, прежде чем просить о дальнейшей помощи.

hairless1 20.06.2019 23:33

Я смог создать словарь, используя этот класс, но возвращаемые ключи <__main__.IPAddress object at 0x0000002DE8D8B5F8> Я не думаю, что правильно понял решение TBH

hairless1 21.06.2019 10:29

@hairless1 Хорошо, я скоро отредактирую с дополнительными инструкциями.

Neil 21.06.2019 13:17

@hairless1 см. полный ответ

Neil 21.06.2019 14:28

Нил: Во-первых, я хотел бы поблагодарить вас за ваше терпение и время, чтобы объяснить мне это. Я смог реализовать решения и многому научился благодаря вашим подробным объяснениям.

hairless1 22.06.2019 13:31

Другие вопросы по теме

Похожие вопросы