当关键字不明时从字典中删除项目


112

按值从字典中删除某项的最佳方法是什么,即当该项的键未知时?这是一个简单的方法:

for key, item in some_dict.items():
    if item is item_to_remove:
        del some_dict[key]

有更好的方法吗?迭代字典时从字典中进行变异(删除项目)有什么问题吗?


1
在迭代过程中禁止突变dict的下划线原因是因为内部存在迭代顺序,如果您对键进行突变,则该顺序将被破坏,从而导致未知行为。
Spectral

Answers:


92

请注意,您当前正在测试对象的身份(isTrue当两个操作数由内存中的同一对象表示时才返回-与相等的两个对象并不总是这样==)。如果您故意这样做,则可以将代码重写为

some_dict = {key: value for key, value in some_dict.items() 
             if value is not value_to_remove}

但这可能无法满足您的要求:

>>> some_dict = {1: "Hello", 2: "Goodbye", 3: "You say yes", 4: "I say no"}
>>> value_to_remove = "You say yes"
>>> some_dict = {key: value for key, value in some_dict.items() if value is not value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 3: 'You say yes', 4: 'I say no'}
>>> some_dict = {key: value for key, value in some_dict.items() if value != value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 4: 'I say no'}

所以您可能想要!=代替is not


2
那是字典压缩吗?他们何时添加?
Buttons840 2011年

4
您可以some_dict.iteritems()在此处使用并将put forifstatement放在单独的行上以提高可读性
jfs

3
我相信Python 2.7中添加了字典理解功能。
mithrandi 2011年

2
@JF Sebastian:我使用的是Python 3,iteritems现在是items。在Python 2.7中,iteritems()确实更好。
Tim Pietzcker 2011年

1
@ Buttons840 在PEP 274字典显示中被称为dict comprehensions。正如PEP所说,它们是在2.7添加的,是向后移植的3.x专长。或者,您可以dict()提供一个合适的生成器表达式2.4。meta:可以浏览此处的点子以查找内容。
n611x007

120

dict.pop(key[, default])方法允许您在知道密钥时删除项目。如果删除该项目,则返回键处的值,否则返回传递为的值default。查看文档

例:

>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}

4
OP询问密钥何时未知
nmz787,17年


42

delpop()之间的简单比较:

import timeit
code = """
results = {'A': 1, 'B': 2, 'C': 3}
del results['A']
del results['B']
"""
print timeit.timeit(code, number=100000)
code = """
results = {'A': 1, 'B': 2, 'C': 3}
results.pop('A')
results.pop('B')
"""
print timeit.timeit(code, number=100000)

结果:

0.0329667857143
0.0451040902256

因此,delpop()快。


6
但是,性能差异不是很大,如果您想避免引发异常,则可以提供的第二个参数pop()(如@ n-1-1所做的那样)-这不是del操作员的选择。
Alex Dupuy 2014年

1
作为该问题的辅助,但我也一直在努力理解timeit。感谢您提供的明确示例。
Adam_G

OP询问密钥何时未知。该答案假定密钥是已知的。
让·弗朗索瓦·科贝特

7

items()返回一个列表,而该列表正是您要迭代的列表,因此在此循环中更改dict并不重要。如果您使用的是iteritems()替代方法,则在循环中更改dict 是有问题的viewitems()在Python 2.7中同样如此。

我想不出一种更好的方法来按值从字典中删除项目。


7

我将建立一个需要删除的密钥列表,然后将其删除。它简单,高效,并且避免了同时迭代和变异字典的任何问题。

keys_to_remove = [key for key, value in some_dict.iteritems()
                  if value == value_to_remove]
for key in keys_to_remove:
    del some_dict[key]

OP询问密钥何时未知。该答案假定密钥是已知的。
让·弗朗索瓦·科贝特


1
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]

0

正如您所建议的,在迭代时从字典中删除项目没有任何问题。注意多个线程同时使用同一字典,这可能会导致KeyError或其他问题。

当然,请参阅http://docs.python.org/library/stdtypes.html#typesmapping中的文档


for k,v in d.iteritems(): del d[k]会给RuntimeError: dictionary changed size during iteration。请参阅mithrandi的说明。
Buttons840 2011年

1
当然,d.iteritems()不是原始海报的迭代方式,也不是我在回答中所指的内容。
Thane Anthem

0

这就是我要做的。

for key in some_dict.keys():
    if some_dict[key] == item_to_remove:
        some_dict.pop(key)
        break
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.