如何从 key/initial 计数对列表中初始化计数器?

How do I initialize a Counter from a list of key/initial counts pairs?

如果我有一个 (key, value) 对序列,我可以像这样快速初始化一个字典:

>>> data = [ ('a', 1), ('b', 2) ]
>>> dict(data) 
{'a': 1, 'b': 2} 

我想用 Counter 字典做同样的事情;但是怎么办?构造函数和 update() 方法都将有序对视为键,而不是键值对:

>>> from collections import Counter
>>> Counter(data)
Counter({('a', 1): 1, ('b', 2): 1})

我能做到的最好的办法是使用一个临时字典,它很丑而且不必要地迂回:

>>> Counter(dict(data))
Counter({'b': 2, 'a': 1})

有没有正确的方法从 (key, count) 对列表中直接初始化 Counter?我的用例涉及从文件中读取大量保存的计数(使用唯一键)。

我会做一个循环:

for obj, cnt in [ ('a', 1), ('b', 2) ]:
    counter[obj] = cnt

您也可以只调用父 dict.update 方法:

>>> from collections import Counter
>>> data = [ ('a', 1), ('b', 2) ]
>>> c = Counter()
>>> dict.update(c, data)
>>> c
Counter({'b': 2, 'a': 1})

最后,你原来的解决方案没有任何问题:

Counter(dict(list_of_pairs))

创建字典或计数器的昂贵部分是散列所有键并定期调整大小。字典制作完成后,将其转换为计数器非常便宜,大约与 dict.copy() 一样快。哈希值被重用,最终的计数器哈希 table 被预先调整大小(不需要调整大小)。

来自 docs:

Elements are counted from an iterable or initialized from another mapping (or counter)

所以是一个没有,需要转成映射然后初始化Counter是的当你用dict初始化时这是正确的举动。

更新

我同意@RaymondHettinger 代码看起来不错,实际上它更快

from collections import Counter
from random import choice
from string import ascii_letters
a=[(choice(ascii_letters), i) for i in range(100)]

使用 Python 3.6.1 和 IPython 6

进行测试

初始化 dict:

%%timeit
c1=Counter(dict(a))

输出

12.1 µs ± 342 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

更新 dict.update()

%%timeit    
c2=Counter()
dict.update(c2, a)

输出:

7.21 µs ± 236 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

如果 (key, value) 对中的键列表已经是唯一的——没有重复——你可以使用 Raymond Hettinger 的 .

请注意,如果存在重复键,您只能获取任何给定键的最后一个值:

>>> data=[ ('a', 1), ('b', 2), ('a', 3), ('b', 4) ]
>>> c=Counter()
>>> dict.update(c, data)
>>> c
Counter({'b': 4, 'a': 3})      # note 'a' and 'b' are only the last value...

dict相同:

>>> Counter(dict(data))
Counter({'b': 4, 'a': 3})

但是 Counters 最常用于计算总数,包括重复项。如果你想要 'a' 和 'b' 条目的总和,你需要遍历所有对:

>>> c=Counter()
>>> for k, v in data:
...    c[k]+=v
... 
>>> c
Counter({'b': 6, 'a': 4})        # the sum of the 'k' entries given 'v'