【问题标题】:How do I initialize a Counter from a list of key/initial counts pairs?如何从键/初始计数对列表中初始化计数器?
【发布时间】:2017-10-05 02:50:21
【问题描述】:

如果我有一系列 (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?我的用例涉及从文件中读取大量保存的计数(使用唯一键)。

【问题讨论】:

  • "显式优于隐式。"为什么您的列表应该与其他可迭代对象区别对待,因为它的形式可以转换为dict
  • 我不要特殊处理,我要不同的初始化路径。
  • 如果您真的在处理“大量保存的文件计数”,您可能应该使用pandasnumpy(结构化数组)。我不知道我们在这里讨论的是什么大小,但在某些时候,同构数组的内存优势(以及特定于 dtype 的操作实现)会派上用场。

标签: python python-3.x data-structures counter python-internals


【解决方案1】:

我只想做一个循环:

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))

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

【讨论】:

  • 注意:很好的解决方案,但仅适用于键列表已经是独一无二的。如果你有类似[ ('a', 1), ('b', 2), ('a', 3), ('b', 4) ] 的东西,你需要遍历所有的对来得到我认为的总数,不是吗? OP 确实注意到列表中的键实际上是否唯一。
  • @dawg 第一个解决方案很容易适应 counter[obj] += cnt 的重复键。
  • 是的,这就是我的观点:如果你想要总计,你必须循环。谢谢!
【解决方案2】:

来自docs

元素从一个可迭代对象中计数或从另一个映射(或计数器)初始化

所以它是一个,你需要将它转换为映射然后初始化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)

【讨论】:

  • 嗯,确实这看起来并不令人鼓舞。谢谢。
【解决方案3】:

如果您在 (key, value) 对中的密钥列表已经是唯一的(没有重复),您可以使用 Raymond Hettinger 的 great solution

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

>>> 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'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 2016-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    相关资源
    最近更新 更多