Python中计算列表中元素出现次数的惯用方法是什么?

9

这是我做的。在Python中有更好的方法吗?

for k in a_list:   
  if kvMap.__contains__(k):
    kvMap[k] += 1   
  else:
    kvMap[k] = 1

谢谢。

6个回答

16

使用 defaultdict

from collections import defaultdict
kvmap= defaultdict(int)
for k in a_list:
    kvmap[k] += 1

我第一次遇到defaultdict是在Peter Norvig的拼写纠正文章中。他只用了几行代码,就将一个单词文件转换成了一个以单词为键、以计数为值的字典。非常酷。http://www.norvig.com/spell-correct.html - hughdbrown

9

单个元素:

a_list.count(k)

所有元素:

counts = dict((k, a_list.count(k)) for k in set(a_list))

这不是相当低效吗?你将列表转换为集合,对其进行迭代,并调用计数(每个集合中的项目可能是O(N))。 - Dana
你说得对,它很可能是O(n^2)的,尽管我认为它在Python的某种程度上很有趣。 - John Novatnack
使用生成器表达式代替列表推导已经足够了。此外,我认为使用元组代替内部列表看起来更好。 - user3850

7

我觉得这段代码看起来还不错。它很简单易懂,符合 Pythonic 的编码风格。

你可以稍微精简一下:

for k in a_list:
     kvMap[k] = 1 + kvMap.get(k,0)

那就是我要发布的内容! - hasen

6

这是一个老问题,但考虑到将值添加到 defaultdict(int) 是如此普遍的用途,因此 collections 自 Python 2.7 版本以来就为其提供了一个特殊的名称。

>>> from collections import Counter
>>> Counter([1, 2, 1, 1, 3, 2, 3, 4])
Counter({1: 3, 2: 2, 3: 2, 4: 1})
>>> Counter("banana")
Counter({'a': 3, 'n': 2, 'b': 1})

3

另一种解决方案是利用 setdefault():

for k in a_list:
    kvMap[k] = kvMap.setdefault(k, 0) + 1

1
如果你的列表已经排序,另一种方法是使用itertools.groupby。这可能不是最有效的方法,但它仍然很有趣。它返回一个项目和计数的字典:
>>> import itertools
>>> l = [1,1,2,3,4,4,4,5,5,6,6,6,7]
>>> dict([(key, len([e for e in group]))
          for (key, group)
          in itertools.groupby(l)])
{1: 2, 2: 1, 3: 1, 4: 3, 5: 2, 6: 3, 7: 1}

外部列表推导式并不必要;生成器表达式就足够了。 - user3850
返回翻译文本:dict((key, len(list(group))) for (key, group) in itertools.groupby(l)) - nosklo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接