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






РЕДАКТИРОВАТЬ Этот пост теперь состоит из трех частей:
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. Я бы порекомендовал прочитать об этом.
Спасибо за ответ. Я не могу честно сказать, что понимаю, но я попытаюсь понять, прежде чем просить о дальнейшей помощи.
Я смог создать словарь, используя этот класс, но возвращаемые ключи <__main__.IPAddress object at 0x0000002DE8D8B5F8> Я не думаю, что правильно понял решение TBH
@hairless1 Хорошо, я скоро отредактирую с дополнительными инструкциями.
@hairless1 см. полный ответ
Нил: Во-первых, я хотел бы поблагодарить вас за ваше терпение и время, чтобы объяснить мне это. Я смог реализовать решения и многому научился благодаря вашим подробным объяснениям.
Не могли бы вы предоставить желаемый результат?