如何在迭代字典时删除其中的项目?
- 2025-01-09 08:47:00
- admin 原创
- 92
问题描述:
我可以在迭代 Python 字典时删除其中的项目吗?
我想从字典中删除不满足特定条件的元素,而不是创建一个全新的字典。以下是一个好的解决方案吗?或者有更好的方法吗?
for k, v in mydict.items():
if k == val:
del mydict[k]
解决方案 1:
对于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来说很好,但RuntimeError
对于Python 3来说却引发了一个问题:
RuntimeError:字典在迭代过程中改变了大小。
发生这种情况是因为mydict.keys()
返回的是迭代器而不是列表。正如评论中指出的那样,只需将其转换mydict.keys()
为列表list(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()
下列方法:
>>> for k, v in mydict.items():
... if v == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
解决方案 2:
您也可以分两步进行:
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)
解决方案 3:
而是对副本进行迭代,比如items()
:
for k, v in list(mydict.items()):
解决方案 4:
您无法在迭代集合时对其进行修改。这样会造成混乱 - 最明显的是,如果您被允许删除并删除了当前项目,迭代器将不得不继续前进 (+1),而下一次调用next
将带您超越该步骤 (+2),因此您最终会跳过一个元素(即您删除的元素后面的元素)。您有两个选择:
复制所有键(或值,或两者,取决于您的需要),然后迭代这些键。您可以使用
.keys()
et al 来实现此目的(在 Python 3 中,将生成的迭代器传递给list
)。但可能会严重浪费空间。像往常一样迭代
mydict
,将要删除的键保存在单独的集合中to_delete
。迭代完成后,从中mydict
删除所有项目。与第一种方法相比,可以节省一些空间(取决于删除了多少个键以及保留了多少个键),但也需要多写几行。to_delete
`mydict`
解决方案 5:
您可以使用词典理解。
d = {k:d[k] for k in d if d[k] != val}
解决方案 6:
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 中运行。
解决方案 7:
使用 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 )
# {}
解决方案 8:
您可以先建立一个要删除的键列表,然后遍历该列表并删除它们。
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]
解决方案 9:
如果您要删除的项目始终位于字典迭代的“开始”处,那么有一种方法可能很合适
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 中是这样。
解决方案 10:
我在 Python3 中尝试了上述解决方案,但当我将对象存储在字典中时,这个解决方案似乎是唯一对我有用的解决方案。基本上,你复制 dict() 并对其进行迭代,同时删除原始字典中的条目。
tmpDict = realDict.copy()
for key, value in tmpDict.items():
if value:
del(realDict[key])
解决方案 11:
单行:
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
}
解决方案 12:
另一种好用且有效的方法是使用部分函数
next((partial(d.pop, k) for k in d if k == v), partial(print, f"{v} key not found"))()