在Python中,我可以在遍历字典时删除字典中的项吗?
我想从字典中删除不符合特定条件的元素,而不是创建一个全新的字典。以下是一个好的解决方案,还是有更好的方法?
for k, v in mydict.items():
if k == val:
del mydict[k]
在Python中,我可以在遍历字典时删除字典中的项吗?
我想从字典中删除不符合特定条件的元素,而不是创建一个全新的字典。以下是一个好的解决方案,还是有更好的方法?
for k, v in mydict.items():
if k == val:
del mydict[k]
在迭代集合时不能修改集合。这种方式是疯狂的——最明显的是,如果你被允许删除和删除当前项,迭代器将不得不移动(+1),而下一次调用next将超出(+2),所以你最终会跳过一个元素(在你删除的元素后面的那个元素)。你有两个选择:
Copy all keys (or values, or both, depending on what you need), then iterate over those. You can use .keys() et al for this (in Python 3, pass the resulting iterator to list). Could be highly wasteful space-wise though. Iterate over mydict as usual, saving the keys to delete in a seperate collection to_delete. When you're done iterating mydict, delete all items in to_delete from mydict. Saves some (depending on how many keys are deleted and how many stay) space over the first approach, but also requires a few more lines.
对于Python 3+:
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
>>> for k in list(mydict.keys()):
... if mydict[k] == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
其他答案在Python 2中工作得很好,但在Python 3中会引发RuntimeError:
RuntimeError:在迭代过程中字典改变了大小。
这是因为mydict.keys()返回的是一个迭代器而不是一个列表。 正如在评论中指出的那样,只需将mydict.keys()转换为逐个列表的列表(mydict.keys()),它就应该工作。
对于Python 2:
在控制台中进行的一个简单测试显示,在遍历字典时不能修改它:
>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
... if k == 'two':
... del mydict[k]
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
正如delnan的回答中所述,当迭代器试图移动到下一个条目时,删除条目会导致问题。相反,使用keys()方法获取键的列表并使用它:
>>> for k in mydict.keys():
... if k == 'two':
... del mydict[k]
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
如果你需要根据items的值进行删除,请使用items()方法:
>>> for k, v in mydict.items():
... if v == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
你也可以分两步来做:
remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]
我最喜欢的方法通常是创建一个新词典:
# Python 2.7 and 3.x
mydict = { k:v for k,v in mydict.items() if k!=val }
# before Python 2.7
mydict = dict((k,v) for k,v in mydict.iteritems() if k!=val)
在python3中,迭代dic.keys()将引发字典大小错误。你可以用这种替代方式:
使用python3测试,它工作正常,并且没有引发错误“迭代期间字典更改大小”:
my_dic = { 1:10, 2:20, 3:30 }
# Is important here to cast because ".keys()" method returns a dict_keys object.
key_list = list( my_dic.keys() )
# Iterate on the list:
for k in key_list:
print(key_list)
print(my_dic)
del( my_dic[k] )
print( my_dic )
# {}
您可以首先构建一个要删除的键的列表,然后遍历该列表删除它们。
dict = {'one' : 1, 'two' : 2, 'three' : 3, 'four' : 4}
delete = []
for k,v in dict.items():
if v%2 == 1:
delete.append(k)
for i in delete:
del dict[i]
使用列表(mydict)是最干净的:
>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k in list(mydict):
... if k == 'three':
... del mydict[k]
...
>>> mydict
{'four': 4, 'two': 2, 'one': 1}
这对应于列表的并行结构:
>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist): # or mylist[:]
... if k == 'three':
... mylist.remove(k)
...
>>> mylist
['one', 'two', 'four']
它们都可以在python2和python3中工作。
我在Python3中尝试了上述解决方案,但在字典中存储对象时,这一个似乎是唯一适合我的解决方案。基本上,您可以创建dict()的副本,并在删除原始字典中的条目的同时遍历该副本。
tmpDict = realDict.copy()
for key, value in tmpDict.items():
if value:
del(realDict[key])
如果想要删除的项总是在dict迭代的“开始”,有一种方法可能是合适的
while mydict:
key, value = next(iter(mydict.items()))
if should_delete(key, value):
del mydict[key]
else:
break
“开头”只保证在某些Python版本/实现中是一致的。例如,来自Python 3.7新提示
dict对象的插入顺序保存特性已被声明为Python语言规范的正式组成部分。
这种方法避免了许多其他答案所建议的字典副本,至少在Python 3中是这样。
一行程序:
my_dict = {k: v for k, v in my_dict.copy().items() if not k == value}
my_dict.copy()对象仅用于迭代,在字典理解范围之外不可用。这避免了编辑当前迭代的对象,正如@user395760在回答中所建议的那样。
为了清晰起见,你可以把它分割成多行:
my_dict = {
k: v
for k, v in my_dict.copy().items()
if not k == value
}