如何在迭代时从字典中删除项目?

时间:2011-03-21 23:23:29

标签: scripting dictionary python

在迭代过程中从Python中删除字典中的项目是否合法?

例如:

for k, v in mydict.iteritems():
   if k == val:
     del mydict[k]

这个想法是从字典中删除不符合某个条件的元素,而不是创建一个新字典,它是被迭代的字典的一个子集。

这是一个很好的解决方案吗?是否有更优雅/有效的方式?

10 个答案:

答案 0 :(得分:277)

修改

这个答案对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}

答案 1 :(得分:78)

您也可以分两步完成:

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)

答案 2 :(得分:18)

迭代时无法修改集合。这种方式就是疯狂 - 最值得注意的是,如果你被允许删除和删除当前项目,迭代器将不得不继续(+1),下一次调用next将超过(+2) ,所以你最终会跳过一个元素(你删除的元素后面的元素)。您有两种选择:

  • 根据您的需要复制所有键(或值,或两者),然后迭代这些键。您可以使用.keys()等(在Python 3中,将生成的迭代器传递给list)。但是在空间方面可能非常浪费。
  • 像往常一样迭代mydict,在单独的集合to_delete中保存要删除的密钥。完成迭代mydict后,请从to_delete中删除mydict中的所有项目。在第一种方法中保存一些(取决于删除的键数量和停留的数量)空间,但还需要更多行。

答案 3 :(得分:16)

迭代副本,例如items()返回的副本:

for k, v in list(mydict.items()):

答案 4 :(得分: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 )
# {}

我使用它时,从使用大量内存的字典中,我想构建另一个字典(包含第一个字典的修改)而不进行“复制”并重载RAM。

答案 5 :(得分:5)

您可以使用词典理解。

d = {k:d[k] for k in d if d[k] != val}

答案 6 :(得分:5)

最干净利用 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 :(得分:4)

您可以先构建一个要删除的密钥列表,然后迭代该列表删除它们。

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]

答案 8 :(得分:1)

我在Python3中尝试了上述解决方案,但是当在dict中存储对象时,这个似乎是唯一适合我的解决方案。基本上你会复制你的dict()并在删除原始字典中的条目时对其进行迭代。

        tmpDict = realDict.copy()
        for key, value in tmpDict.items():
            if value:
                del(realDict[key])

答案 9 :(得分:0)

如果您要删除的项目始终位于字典迭代的“开始”位置,则有一种合适的方法

while mydict:
    key, value = next(iter(mydict.items()))
    if should_delete(key, value):
       del mydict[key]
    else:
       break

“开始”仅保证对于某些Python版本/实现是一致的。例如来自What’s New In Python 3.7

  

dict对象的插入顺序保留性质已声明是Python语言规范的正式组成部分。

这种方式避免了很多其他答案所建议的dict副本,至少在Python 3中如此。