在Python上进行迭代时从字典中删除项目是否合法?
例如:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
这个想法是从字典中删除不满足特定条件的元素,而不是创建一个新字典,该字典是被迭代的字典的子集。
这是一个好的解决方案吗?有没有更优雅/更有效的方法?
在Python上进行迭代时从字典中删除项目是否合法?
例如:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
这个想法是从字典中删除不满足特定条件的元素,而不是创建一个新字典,该字典是被迭代的字典的子集。
这是一个好的解决方案吗?有没有更优雅/更有效的方法?
Answers:
编辑:
此答案不适用于Python3,并且会给出RuntimeError
。
RuntimeError:词典在迭代过程中更改了大小。
发生这种情况是因为mydict.keys()
返回的是迭代器而不是列表。正如注释中所指出的那样,只需将其转换mydict.keys()
为列表即可list(mydict.keys())
,它应该可以工作。
控制台中的一个简单测试显示,在迭代字典时您无法修改字典:
>>> 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()
方法:
>>> for k, v in mydict.items():
... if v == 3:
... del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}
for k, v in list(mydict.items()):
,工作正常在Python 3同为keys()
成为list(keys())
。
RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
python3,因为它使keys()方法成为迭代器,并且不允许在迭代过程中删除dict项。通过添加list()调用,您可以将keys()迭代器转换为列表。因此,当您处于for循环的正文中时,您不再需要遍历字典本身。
您也可以分两个步骤进行操作:
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)
remove
循环方法。
for k in [k for k in mydict if k == val]: del mydict[k]
迭代时不能修改集合。那就是疯狂-最为明显的是,如果允许您删除和删除当前项目,则迭代器将必须继续(+1),下一次调用next
将使您超出该范围(+2),因此您会最终跳过了一个元素(删除的元素后面的一个)。您有两种选择:
.keys()
为此使用et al(在Python 3中,将生成的迭代器传递给list
)。但是在空间上可能会非常浪费。mydict
照常进行迭代,将要保存的密钥保存在单独的collection中to_delete
。当你完成迭代mydict
,删除所有项目to_delete
从mydict
。与第一种方法相比,可以节省一些(取决于删除的键数和剩余的键数)空间,但还需要多几行。You can't modify a collection while iterating it.
这仅适用于字典和朋友,但是您可以在迭代期间修改列表:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
can't
仅对字典和朋友正确,而shouldn't
对列表是正确的。
而是遍历一个副本,例如items()
:
for k, v in list(mydict.items()):
del v
直接使用,因此您已经为每个不再使用的v制作了一个副本,并且无论如何都必须通过键来访问这些项。dict.keys()
是更好的选择。
v
作为删除标准。
使用起来最干净list(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,在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迭代的“开始”,则有一种方法可能合适
while mydict:
key, value = next(iter(mydict.items()))
if should_delete(key, value):
del mydict[key]
else:
break
仅保证“开始”对于某些Python版本/实现是一致的。例如,Python 3.7新增功能
dict对象的插入顺序保留性质已声明是Python语言规范的正式组成部分。
这种方式避免了很多其他答案所暗示的dict副本,至少在Python 3中如此。