обновить счетчик дефолтов в соответствии с наличием кортежей в двух списках - PullRequest
0 голосов
/ 17 ноября 2018

У меня есть два списка, и я хотел бы создать словарь для записи появления кортежей.

Мой текущий код:

tup_to_find_test = [('good', 'pea'), ('leaf', 'sweet')] 
self_per_list_test = [('leaf', 'liquid'), ('leaf', 'sweet'), ('leaf', 'sweet'),('good', 'pea'),('good', 'pea'),('good', 'pea')]
from collections import defaultdict
tup_dict_test = defaultdict(int)
for tup_to_find_test in self_per_list_test:
   tup_dict_test[tup_to_find_test]+=1

Мой результат:

defaultdict(int, {('leaf', 'liquid'): 1, ('leaf', 'sweet'): 1, ('good', 'pea'): 3})

Мой желаемый результат:

('leaf', 'liquid'): 0, ('leaf', 'sweet'): 2, ('good', 'pea'): 3})

Я не знаю, почему счетчик ('leaf', 'liquid') равен 1. Разве целое число по умолчанию defaultdict(int) не равно нулю?Почему я получил 1 за ('leaf', 'liquid') кортеж?

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

Эта строка не делает то, что вы думаете:

for tup_to_find_test in self_per_list_test:
   # ...

Здесь вы повторяете список по элементам , в данном случае это элементы self_per_list_test. фильтрации нет не происходит.Поскольку ваш цикл for повторяется, tup_to_find_test последовательно представляет ('leaf', 'liquid'), ('leaf', 'sweet') и т. Д. Тот факт, что имя совпадает с переменной, которую вы определили ранее, только сбивает с толку.

Вместо этогоВы можете использовать троичный оператор для дифференциации операций:

for item in self_per_list_test:
    tup_dict_test[item] += 1 if item in tup_to_find_test else 0

print(tup_dict_test)

defaultdict(int, {('leaf', 'liquid'): 0, ('leaf', 'sweet'): 2, ('good', 'pea'): 3})

collections.Counter более идиоматичен для Python.Хорошей практикой является использование set для поиска O (1) в пределах словаря.

from collections import Counter

tup_to_find_set = set(tup_to_find_test)
counts = Counter(self_per_list_test)

tup_dict_test = {k: v if k in tup_to_find_set else 0 for k, v in counts.items()}

print(tup_dict_test)

{('leaf', 'liquid'): 0, ('leaf', 'sweet'): 2, ('good', 'pea'): 3}
0 голосов
/ 17 ноября 2018

Не изобретая велосипед. Для этого вы можете использовать counter из замечательной collections стандартной библиотеки модулей.

from collections import Counter

tup_to_find_test = [('good', 'pea'), ('leaf', 'sweet')] 
self_per_list_test = [('leaf', 'liquid'), ('leaf', 'sweet'), ('leaf', 'sweet'),('good', 'pea'),('good', 'pea'),('good', 'pea')]

c = Counter(self_per_list_test)

for key in c:
    if key not in tup_to_find_test:
        c[key] = 0

print(c)

>>Counter({('good', 'pea'): 3, ('leaf', 'sweet'): 2, ('leaf', 'liquid'): 0})

Здесь мы создаем счетчик на основе self_per_list_test и обновляем счетчики до нуля, если он не найден в tup_to_find_test. Надеюсь, это более интуитивный метод решения вашей проблемы.

0 голосов
/ 17 ноября 2018

Разве целое число по умолчанию не равно defaultdict(int) нулю?

Да.

Почему я получил 1 для ('leaf', 'liquid ') tuple?

Вы писали:

tup_dict_test[tup_to_find_test]+=1

То есть найдите текущее значение, которое создает новое значение, установленное на ноль, затем добавьте одно к нему и сохранитерезультат обратно.Полученное значение равно 1.

...