Как получить количество списков с определенным элементом?

У меня есть список списков, который выглядит как

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 к значению для этого ключа.