如何从 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'
如果我有一个 (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'