【问题标题】:Avoid double lookup when updating dictionary integer members更新字典整数成员时避免重复查找
【发布时间】:2014-10-29 19:06:00
【问题描述】:

如果字典包含您可以引用的内容,您可以使用一次字典查找默认或更新它:

d.setdefault('k', []).append(2)

但是,如果字典条目是数字,则无法以相同的方式修改它们:

d.setdefault('k', 0) += 1  # doesn't work

相反,您需要进行两次 dict 查找,一次用于读取,一次用于写入:

d['a'] = d.get('a', 0) + 1

对于具有大量键的字典来说,这似乎不是一个好主意。那么,有没有办法对包含数字的字典进行默认或更新操作?或者,换一种说法,在此类字典上应用默认或更新操作的最高效方式是什么?

【问题讨论】:

  • "对于具有大量键的字典来说,这似乎不是一个好主意。"定义“巨大”。因为它可能有数十万。
  • 足够大以至于字典索引遍历成本很高。如果那是数十万,那就这样吧。
  • 大概几千万吧。并不是说我手头有任何证据……
  • dict 查找只有在您开始获得可观数量的哈希冲突时才会开始变慢 - 这在 32 位系统的数百万条目和 64 位系统的数万亿条目中的某处。

标签: python performance dictionary python-2.6


【解决方案1】:

快速测试表明collections.defaultdict 比您的双重查找快大约 2.5 倍(在 Python 2.6 上测试):

>>> import timeit
>>> s1 = "d = dict((str(n), 0) for n in range(1000000))"
>>> timeit.repeat("d['a'] = d.get('a', 0) + 1", setup=s1)
[0.17711305618286133, 0.17411494255065918, 0.17812514305114746]
>>> s2 = """
... from collections import defaultdict
... d = defaultdict(int, ((str(n), 0) for n in range(1000000)))
... """
>>> timeit.repeat("d['a'] += 1", setup=s2)
[0.07185506820678711, 0.07294416427612305, 0.12155508995056152]

【讨论】:

  • 虽然我喜欢这个想法,但我认为正确的测试是做你所做的,但使用大字典而不是空字典。
  • @Reinderien 没有区别。其他评论者是对的:dict 查找是 O(1)。无论如何,我已经根据您的建议修改了测试设置,结果基本相同,正如预期的那样。具有一千万个项目的 dict 也是如此(一亿个内存不足并导致我机器上的 Python 崩溃)。
猜你喜欢
  • 2012-12-16
  • 2012-01-18
  • 2020-07-15
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-31
  • 2021-03-06
  • 2012-06-10
相关资源
最近更新 更多