如何获得特定元素的列表数量?

问题描述:

我有一个列表的列表,它看起来像如何获得特定元素的列表数量?

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} 

我想知道如果有一个更好的方式来完成我的目标。

使用一个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}) 

如果你喜欢函数式编程也可以养活chainset的 - map PED listOfListsCounter

>>> from collections import Counter 
>>> from itertools import chain 

>>> Counter(chain.from_iterable(map(set, listOfLists))) 
Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1}) 

这与第一种方法完全相同(除了可能稍微快一点)。

我想每一个列表转换为一组在发电机理解计数前传递给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}) 

(这实际上是你做了什么,但上面的代码短裤很多循环和临时列表创建)

你可以不用一个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} 

不是最优雅的,更应该是相当快的。

Counter方法与itertools.chain.from_iterable文体差异的一点可能看起来像

Counter(chain.from_iterable(map(set, listOfLists))) 

演示

>>> 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 
+0

我在CPython 2.7.11上使用'itertools.chain'(〜40%!)获得更快的执行速度。尽管如此,'Counter' +'itertools.chain'的执行速度比我提出的'raw'方法慢4倍。 – zwer

+1

@zwer Eh,取决于我们正在讨论的输入大小。我的解决方案有更多的开销,但如果您增加输入大小,它应该更快。这就是为什么基准测试不是太重要:) – miradulo

+0

的确如此,我只是对我的位置在速度方面的巨大差异感到惊讶,我不习惯“itertools”实际上表现超越,几乎任何东西 - 它们都是通常是较慢的,但更易于阅读的选择:D – zwer

只需转换为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)))) 

这种方法使用一套理解计算独特的条目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计算对入字典解析

+0

不需要再次将您的集合'A'转换为列表或者以列表理解的形式提供集合,生成表达式更好......实际上您可以构建'A '也作为一种理解 – Copperfield

+0

@Copperfield感谢您的建议。我做了一个改变。 – nbryans

这里做这一个班轮是使用循环另一个版本:

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 

所以创建一个名为最后一个空的字典。然后遍历每个列表的每个字母。如果该字母在最终还不存在作为关键字,则创建一个新的关键字和值= 1。否则,加1到该键的值。