#python-3.x
Вопрос:
У меня есть список кортежей под названием «восходящая связь» следующим образом:
uplink is [(6, 26), (15, 26), (26, 48), (26, 65), (48, 26), (48, 92), (65, 26), (65, 92), (88, 26), (92, 48), (92, 65)]
Я хочу идентифицировать кортежи, которые содержат одни и те же записи (не в том же порядке), например (48,92) и (92,48), и добавить один из них в другой список, по нисходящей ссылке, для дальнейшей обработки. Я хочу, чтобы этот дубликат был удален из списка восходящей связи.
То, что я попробовал, заключается в следующем:
for u in uplink:
A = u[0]
B = u[1]
if (A,B) == (B,A):
downlink.append(u)
uplink.remove(u)
Это не работает. Любая помощь была бы чрезвычайно признательна. Спасибо.
Комментарии:
1. Есть ли возможность, что A, B могут быть равны ? Мой текущий ответ потерпит неудачу, если это так, потому
frozenset
что в результате будет только один элемент.
Ответ №1:
Вы можете использовать преимущества счетчиков и морозильных камер:
>>> x = [(6, 26), (15, 26), (26, 48), (26, 65), (48, 26), (48, 92), (65, 26), (65, 92), (88, 26), (9
2, 48), (92, 65)]
>>> from collections import Counter
>>> count = Counter(frozenset({first, second}) for first, second in x)
>>> count
Counter({frozenset({48, 26}): 2, frozenset({65, 26}): 2, frozenset({48, 92}): 2, frozenset({65, 92})
: 2, frozenset({26, 6}): 1, frozenset({26, 15}): 1, frozenset({88, 26}): 1})
>>> [(first, second) for (first, second), count in count.items() if count > 1]
[(48, 26), (65, 26), (48, 92), (65, 92)]
Редактировать
Исправлена одна ошибка в приведенном выше ответе, предполагающая, что первый и второй элементы, передаваемые в frozenset, могут быть равными (для простоты я просто фильтрую их).
from random import randint
import timeit
from collections import Counter
x = [(randint(1, 20), randint(1, 20)) for i in range(100)]
def frozen_set_counter():
global x
count = Counter(frozenset({first, second}) for first, second in x if first != second)
return [(first, second) for (first, second), count in count.items() if count > 1]
def min_max_counter():
global x
count = Counter(((min(first, second), max(first, second)) for first, second in x if first != second))
return [(first, second) for (first, second), count in count.items() if count > 1]
print(timeit.timeit(lambda: frozen_set_counter(), number=10000))
print(timeit.timeit(lambda: min_max_counter(), number=10000))
0.48902677999999994
0.687653337
Комментарии:
1. Вариант заключается в добавлении
(min(first, second), max(first, second))
кортежей вместо замороженного набора. Преимуществом кортежа здесь является несколько более стабильный порядок чисел в каждой паре[(26, 48), (26, 65), (48, 92), (65, 92)]
и отсутствие необходимости преобразования обратно в кортеж (в зависимости от потребностей в выводе).2. Отличная идея 🙂 будет время посмотреть, что быстрее.
3. @user2864740 мин/макс был немного медленнее, вот тест.
4. @Niloct На самом деле я этого не ожидал, интересно! Я ожидал, что производительность будет такой же, используя кортежи для других различий и потенциальной простоты использования. Сохраняется ли это при значительном увеличении N?