Python中从字典中删除特定键的最快方法

10

我正在寻找在python字典中删除特定键的最快/最有效的方法。

以下是一些选项

for k in somedict.keys(): 
    if k.startswith("someprefix"): 
        del somedict[k]
或者
dict((k, v) for (k, v) in somedict.iteritems() if not k.startswith('someprefix'))

逻辑上来说,第一段代码在小字典上应该更快,因为它不会创建字典的副本,而是创建了一个包含所有键的列表,但是双重查找和字典重建很耗时间。而第二段代码在大字典上更快,但需要两倍的内存。

还有更快的方法吗?


@Adam:不行,你不能这样做。在迭代字典时,你不能添加或删除其中的项。 - Ignacio Vazquez-Abrams
@Ignacio:谢谢,已删除评论。 - mechanical_meat
一个特殊情况:如果你的前缀长度是固定的,可以通过前缀维护一个字典列表。这样只需删除列表中的所有键即可。 - user347594
2个回答

18

del不仅更易于理解,而且似乎比pop()稍微快一些:

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "for k in d.keys():" "  if k.startswith('f'):" "    del d[k]"
1000000 loops, best of 3: 0.733 usec per loop

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "for k in d.keys():" "  if k.startswith('f'):" "    d.pop(k)"
1000000 loops, best of 3: 0.742 usec per loop

编辑:感谢Alex Martelli提供了如何进行此基准测试的指导。希望我没有犯任何错误。

首先测量复制所需的时间:

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "d1 = d.copy()"
1000000 loops, best of 3: 0.278 usec per loop

复制字典的基准测试:

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "d1 = d.copy()" "for k in d1.keys():" "  if k.startswith('f'):" "    del d1[k]"
100000 loops, best of 3: 1.95 usec per loop

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "d1 = d.copy()" "for k in d1.keys():" "  if k.startswith('f'):" "    d1.pop(k)"
100000 loops, best of 3: 2.15 usec per loop

减去复制成本后,我们得到pop()的时间为1.872微秒,del的时间为1.672微秒。


@Mike:添加了基准测试,以显示你的方法比使用 pop() 稍快,同时在我看来更易读。 - mechanical_meat
@Adam Bernier 只是因为 pop 返回一个值而 del 不返回。对于更大的字典或更大的值,差异应该是显著的。 - HardQuestions
4
使用timeit的方式不正确,其中的1000000次循环中,999999次都是在一个只有bar键的1个元素字典上运行(-s设置代码不会在每次循环之前重复执行)。您需要创建并修改d1=d.copy()(将此语句作为要由timeit测量的代码的一部分)--这种操作在测量更改数据的代码时非常关键。您可以通过将此类副本添加到所有要计时的变体中,并单独测量 copy,然后从您正在考虑的代码变体的时间中减去其时间来进行标准化(以找到时间比率)。 - Alex Martelli
@Alex:非常感谢你提供如此精确的分析。我希望我在编辑时没有搞砸你的指示。 - mechanical_meat
@Adam,不客气,而且,+1,目前看起来是对的(至少初步检查如此)。 - Alex Martelli
显示剩余2条评论

9
如果字典足够大,生成一个全新的字典可能更合理。
dict((k, v) for (k, v) in somedict.iteritems() if not k.startswith('someprefix'))

1
谢谢,我的第一个解决方案与你的完全相同,有趣的是测试哪个更快。 - HardQuestions

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接