执行以下操作更快:
if foo not in A.keys():
A[foo]=x
或者简单地更新。
A[foo]=x
因为当计算机找到foo条目时,它可以更新它。否则我就需要调用哈希表两次?
谢谢。
if foo not in A.keys():
A[foo]=x
A[foo]=x
因为当计算机找到foo条目时,它可以更新它。否则我就需要调用哈希表两次?
谢谢。
使用内置的update()函数甚至更快。我稍微调整了Steven Rumbalski上面的例子并展示了如何使用update()是最快的。至少有两种方法可以使用它(使用元组列表或另一个字典)。前者(在update_method1中显示)是最快的。请注意,我还改变了关于Steven Rumbalski的例子的其他一些事情。我的字典将每个有精确地100,000个键,但新值有10%的机会不需要更新。这种重复的机会取决于用于更新字典的数据的性质。在我的机器上,在所有情况下,我的update_method1都是最快的。
import timeit
setup = """
import random
random.seed(0)
item_count = 100000
existing_dict = dict([(str(i), random.randint(1, 10)) for i in xrange(item_count)])
items = [(str(i), random.randint(1, 10)) for i in xrange(item_count)]
items_dict = dict(items)
"""
in_dict = """
for k, v in items:
if k not in existing_dict:
existing_dict[k] = v
"""
set_default = """
for k, v in items:
existing_dict.setdefault(k, v)
"""
straight_add = """
for k, v in items:
existing_dict[k] = v
"""
update_method1 = """
existing_dict.update(items)
"""
update_method2 = """
existing_dict.update(items_dict)
"""
print 'in_dict ', timeit.Timer(in_dict, setup).timeit(1000)
print 'set_default ', timeit.Timer(set_default, setup).timeit(1000)
print 'straight_add ', timeit.Timer(straight_add, setup).timeit(1000)
print 'update_method1 ', timeit.Timer(update_method1, setup).timeit(1000)
print 'update_method2 ', timeit.Timer(update_method2, setup).timeit(1000)
这段代码产生了以下结果:
in_dict 10.6597309113
set_default 19.3389420509
straight_add 11.5891621113
update_method1 7.52693581581
update_method2 9.10132408142
可以直接将item添加到字典中,无需检查其是否已存在。我使用了三种不同的方法向一个字典中添加了100000个item,并使用timeit模块计时。
if k not in d: d[k] = v
d.setdefault(k, v)
d[k] = v
第三种选项是最快的,但差距不大。
[ 实际上,我也尝试过if k not in d.keys(): d[k] = v
,但速度要慢300倍(每次迭代都会构建一个键列表并执行线性搜索),这使我的测试变得非常缓慢,所以我在这里将其排除了。 ]
以下是我的代码:
import timeit
setup = """
import random
random.seed(0)
item_count = 100000
# divide key range by 5 to ensure lots of duplicates
items = [(random.randint(0, item_count/5), 0) for i in xrange(item_count)]
"""
in_dict = """
d = {}
for k, v in items:
if k not in d:
d[k] = v
"""
set_default = """
d = {}
for k, v in items:
d.setdefault(k, v)
"""
straight_add = """
d = {}
for k, v in items:
d[k] = v
"""
print 'in_dict ', timeit.Timer(in_dict, setup).timeit(1000)
print 'set_default ', timeit.Timer(set_default, setup).timeit(1000)
print 'straight_add ', timeit.Timer(straight_add, setup).timeit(1000)
结果如下:
in_dict 13.090878085
set_default 21.1309413091
straight_add 11.4781760635
注意:这些都是相当无意义的。我们每天都会收到很多关于在Python中如何更快地执行x或y的问题,而大多数情况下,明显这个问题是在出现任何性能问题之前就被问出来了。我的建议是,专注于编写你能写出的最清晰的程序,如果它太慢了,就使用分析工具找到需要优化的地方进行优化。根据我的经验,我几乎从来没有使用过分析和优化步骤。从问题描述中可以看出,在你的程序中,字典存储不会是主要的瓶颈。
if foo not in A.keys():
A[foo] = x
非常缓慢,因为A.keys()
会创建一个列表,需要 O(N) 时间来解析。
if foo not in A:
A[foo] = x
之所以更快,是因为检查A
中是否存在foo
只需花费O(1)的时间。
A[foo] = x
更好的方法是,因为您已经有了对象x
,只需将指针添加到A
中(如果它不存在)。
foo not in A.keys()
在Python 2中,将创建一个带有键的新列表,然后对其执行线性搜索。这保证会更慢(尽管我主要反对它是因为有更快速且更优雅/惯用的替代方案)。
A[foo] = x
和
if foo not in A:
A[foo] = x
如果A [foo]
已经存在但不是x
,则两者是不同的。但由于您“知道”A [foo]
将是x
,因此从语义上讲并不重要。无论如何,在性能方面都很好(很难在没有基准测试的情况下确定,尽管直觉告诉我if
比复制指针需要更多时间)。
因此,答案显然是:选择代码更短且同样清晰的那个(第一个)。
assert(A[foo]==x)
这将告诉您您的假设是否错误!
foo
不在 A
中,这将会失败并抛出 KeyError
异常。但是,如果程序开始给出错误的结果,可以使用 if foo in A: assert A[foo] == x
进行断言。 - user395760肯定有比你的第一个示例更快的方法。但我怀疑直接更新会比任何测试都要快。
A.setdefault(foo, x)
但我不确定它是否比 if not A.has_key(foo): A[foo] = x
更快。需要进行测试。
setdefault
,但我怀疑它是否比A[foo] = x
更快。 - Douglas LeederA[foo]=x
不会实现原作者想要的功能。根据代码片段,在字典中不存在键 foo 时才会添加 foo:x
。 - khachikA[foo]=x
比 A.setdefault(foo, x)
快(1/1.5)。所以如果旧值可以被覆盖,你可以直接重新赋值。 - khachik
timeit
时,你学到了什么?请发布结果。 - S.Lotttimeit
的答案。 - Steven Rumbalski