#python #python-3.x #python-2.7
Вопрос:
У меня есть словарь кортежей, как показано на рисунке: mydict = {0: (12, 89), 1: (23, 78), 2: (34, 67), 3: (45, 56), 4: (56, 45), 5: (67, 34), 6: (78, 23), 7: (89, 12)}
Здесь последние четыре элемента (56, 45), (67, 34), (78, 23), (89, 12) являются дубликатами первых четырех элементов, но расположены в другом порядке, и я хочу его удалить.
Я использую приведенный ниже подход, но это приведет к удалению только в том случае, если кортежи одинаковы. Например: (12, 89) = (12, 89).
values = mydict.values()
for x, y in mydict.items():
for i in values:
if i not in mydict.items():
print("Result", x, y)
Каков эффективный способ получить желаемый результат ? Я хочу сравнить, может быть, например (12, 89) и (89, 12), и поскольку в нем есть те же элементы, я хочу удалить один из них.
Кто-нибудь может мне помочь с этим ?
Комментарии:
1. Вам нужно создать новый диктант, в котором будут отсортированы все значения. Это позволит выполнить сравнение‘==‘.
Ответ №1:
Ваши варианты зависят от того, заботитесь ли вы о порядке кортежей после удаления и упорядочен ли ваш входной словарь (python 3.6 ).
Никаких заказов
Решение 1 (Python 3.6 )
В случае, если вы не заботитесь о порядке и используете python 3.6 , вы можете использовать следующий трюк:
filtered = {tuple(sorted(val)): key for key, val in mydict.items().__reversed__()}
restored = {val: key for key, val in filtered.items()}
{0: (12, 89), 1: (23, 78), 2: (34, 67), 3: (45, 56)}
Идея построена на концепции, согласно которой python dict сортируется на 3.6 , это означает, что первые ключи будут вставлены позже в dict из-за __reversed__
порядка. В первой строке перевернуты ключ и значение, следовательно, любые повторяющиеся значения будут перезаписаны (именно поэтому мы делаем это в обратном порядке, поэтому последние элементы перезаписываются в более ранних элементах). Вторая строка возвращает ключ и значение обратно.
Важное замечание в приведенном выше решении заключается в том, что теперь кортежи отсортированы. Это означает , что если бы вы имели 0: (89, 12)
, это стало бы 0: (12, 89)
вместо этого.
Решение 2 (Любая версия)
Первый трюк действительно зависит от информации о том, что более высокие значения ключа могут быть устранены путем замены их более низкими значениями ключа. Чтобы обеспечить это условие, мы можем создать упорядоченную структуру, отсортировав их на основе отсортированного значения ( x[1]
) и их ключа ( x[0]
).
ordered = sorted(mydict.items(), key=lambda x: (sorted(x[1]), x[0])).__reversed__()
Что приводит к следующему порядку
[(4, (56, 45)), (3, (45, 56)), (5, (67, 34)), (2, (34, 67)), (6, (78, 23)), (1, (23, 78)), (7, (89, 12)), (0, (12, 89))]
Затем повторно нанесите раствор 1:
filtered = {tuple(sorted(val)): key for key, val in ordered}
restored = {val: key for key, val in filtered.items()}
Мы закончили.
Поддерживайте порядок
Решение 1 (Python 3.6 )
filtered = {tuple(sorted(val)): key for key, val in mydict.items().__reversed__()}
restored = {val: mydict[val] for key, val in filtered.items()}
Аналогично первому решению без порядка, но теперь использует ключ, чтобы получить исходное значение из первого словаря. Поэтому значения будут прежними, другими словами 0: (89, 12)
, останутся 0: (89, 12)
.
Решение 2 (Любая версия)
Аналогично решению в неупорядоченном варианте, мы повторно используем исходный словарь для создания правильных индексов.
ordered = sorted(mydict.items(), key=lambda x: (sorted(x[1]), x[0])).__reversed__()
filtered = {tuple(sorted(val)): key for key, val in ordered}
restored = {val: mydict[val] for key, val in filtered.items()}
Примечания
Чтобы увидеть разницу между решениями, было бы желательно поменять порядок 0: (12, 89)
на 0: (89, 12)
.
Все вместе взятое:
mydict = {0: (89, 12), 1: (23, 78), 2: (34, 67), 3: (45, 56), 4: (56, 45),
5: (67, 34), 6: (78, 23), 7: (89, 12)}
if __name__ == '__main__':
filtered = {tuple(sorted(val)): key for key, val in mydict.items().__reversed__()}
restored = {val: key for key, val in filtered.items()}
print(restored)
restored = {val: mydict[val] for key, val in filtered.items()}
print(restored)
ordered = list(sorted(mydict.items(), key=lambda x: (sorted(x[1]), x[0])).__reversed__())
filtered = {tuple(sorted(val)): key for key, val in ordered}
restored = {val: key for key, val in filtered.items()}
print(restored)
ordered = sorted(mydict.items(), key=lambda x: (sorted(x[1]), x[0])).__reversed__()
filtered = {tuple(sorted(val)): key for key, val in ordered}
restored = {val: mydict[val] for key, val in filtered.items()}
print(restored)
И вывод с использованием python 3.9:
{0: (12, 89), 1: (23, 78), 2: (34, 67), 3: (45, 56)} # No order python 3.6
{3: (45, 56), 2: (34, 67), 1: (23, 78), 0: (12, 89)} # No order any version
{0: (89, 12), 1: (23, 78), 2: (34, 67), 3: (45, 56)} # Order python 3.6
{3: (45, 56), 2: (34, 67), 1: (23, 78), 0: (89, 12)} # Order any version
Редактировать
Как указано Jasmijn
, более правильным решением для случаев, когда порядок не имеет значения, было бы заменить tuple(sorted(val))
на frozenset(val)
.
Комментарии:
1. Если порядок не важен
frozenset
, может быть более подходящим типом данных, чем сортированныйtuple
s.2. Это действительно лучшее решение. Я вставил его в ответ, чтобы указать вариант. Спасибо!