Как получить количество списков с определенным элементом?
У меня есть список списков, который выглядит как
listOfLists = [
['a','b','c','d'],
['a','b'],
['a','c'],
['c','c','c','c']
]
Я хочу подсчитать количество списков, которые имеют определенный элемент. Например, мой вывод должен быть
{'a':3,'b':2,'c':3,'d':1}
Как вы можете видеть, мне не нужен общий счет элемента. В случае "c"
, хотя его общий счет равен 5, выход равен 3, поскольку он встречается только в 3 списках.
Я использую счетчик, чтобы получить подсчеты. То же самое можно увидеть ниже.
line_count_tags = []
for lists in lists_of_lists:
s = set()
for element in lists:
s.add(t)
lines_count_tags.append(list(s))
count = Counter([count for counts in lines_count_tags for count in counts])
Итак, когда я печатаю счет, я получаю
{'a':3,'c':3,'b':2,'d':1}
Я хочу знать, есть ли лучший способ достичь моей цели.
Ответы
Ответ 1
Используйте Counter
и конвертируйте каждый список в набор. set
удалит любые дубликаты из каждого списка, чтобы вы не учитывали повторяющиеся значения в одном списке:
>>> from collections import Counter
>>> Counter(item for lst in listOfLists for item in set(lst))
Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1})
Если вам нравится функциональное программирование, вы также можете передать chain
из set
- map
ped listOfLists
в Counter
:
>>> from collections import Counter
>>> from itertools import chain
>>> Counter(chain.from_iterable(map(set, listOfLists)))
Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1})
Это полностью эквивалентно (за исключением, может быть, немного быстрее) первого подхода.
Ответ 2
Я бы преобразовал каждый список в виде набора перед подсчетом в понимании генератора, переданного в Counter
:
import collections
print(collections.Counter(y for x in listOfLists for y in set(x)))
результат:
Counter({'a': 3, 'c': 3, 'b': 2, 'd': 1})
(это практически то, что вы сделали, но приведенный выше код замыкает много циклов и временное создание списка)
Ответ 3
Вы можете сделать это без Counter
:
result = {}
for lis in listOfLists:
for element in set(lis):
result[element] = result.get(element, 0) + 1
print result # {'a': 3, 'c': 3, 'b': 2, 'd': 1}
Не самый элегантный, но должен быть значительно быстрее.
Ответ 4
Немного стилистической разницы в подходе Counter
с itertools.chain.from_iterable
может выглядеть как
Counter(chain.from_iterable(map(set, listOfLists)))
Demo
>>> from itertools import chain
>>> from collections import Counter
>>> Counter(chain.from_iterable(map(set, listOfLists)))
Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1})
Грубый тест
%timeit Counter(item for lst in listOfLists for item in set(lst))
100000 loops, best of 3: 13.5 µs per loop
%timeit Counter(chain.from_iterable(map(set, listOfLists)))
100000 loops, best of 3: 12.4 µs per loop
Ответ 5
Просто преобразуйтесь в set
, сгладьте с помощью itertools.chain.from_iterable
, а затем введите Counter
.
from collections import Counter
from itertools import chain
inp = [
['a','b','c','d'],
['a','b'],
['a','c'],
['c','c','c','c']
]
print(Counter(chain.from_iterable(map(set, inp))))
Ответ 6
Этот подход вычисляет уникальные записи в listOfLists
с использованием набора значений, а затем подсчитывает вхождения в каждом списке, используя понимание словаря
A = {val for s in listOfLists for val in s}
d = {i: sum( i in j for j in listOfLists) for i in A}
print(d) # {'a': 3, 'c': 3, 'b': 2, 'd': 1}
Я признаю это немного уродливым, но это возможное решение (и классное использование понимания словаря).
Вы также можете сделать это одним слоем, переместив вычисление A
прямо в понимание словаря
Ответ 7
Вот еще одна версия с использованием циклов:
listOfLists = [
['a','b','c','d'],
['a','b'],
['a','c'],
['c','c','c','c']
]
final = {}
for lst in listOfLists:
for letter in lst:
if letter in final:
final[letter] += 1
else:
final[letter] = 1
Итак, создайте пустой словарь, называемый final. Затем пропустите каждую букву каждого списка. Создайте новый ключ и value = 1, если письмо еще не существует в финале в качестве ключа. В противном случае добавьте 1 к значению для этого ключа.