How to delete items from a dictionary while iterating over it?

Is it legitimate to delete items from a dictionary in Python while iterating over it?

For example:

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

The idea is to remove elements that don't meet a certain condition from the dictionary, instead of creating a new dictionary that's a subset of the one being iterated over.

Is this a good solution? Are there more elegant/efficient ways?


A simple test in the console shows you cannot modify a dictionary while iterating over it:

>>> 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

As stated in delnan's answer, deleting entries causes problems when the iterator tries to move onto the next entry. Instead, use the keys() method to get a list of the keys and work with that:

>>> for k in mydict.keys():
...    if k == 'two':
...        del mydict[k]
...
>>> mydict
{'four': 4, 'three': 3, 'one': 1}

If you need to delete based on the items value, use the items() method instead:

>>> for k, v in mydict.items():
...     if v == 3:
...         del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}

EDIT:

Above will not work for Python3 and will give a RuntimeError .

RuntimeError: dictionary changed size during iteration.

This happens because mydict.keys() returns an iterator not a list. As pointed out in comments simply convert mydict.keys() to a list by list(mydict.keys()) and it should work.


You could also do it in two steps:

remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]

My favorite approach is usually to just make a new dict:

# 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)

You can't modify a collection while iterating it. That way lies madness - most notably, if you were allowed to delete and deleted the current item, the iterator would have to move on (+1) and the next call to next would take you beyond that (+2), so you'd end up skipping one element (the one right behind the one you deleted). You have two options:

  • 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.
  • 链接地址: http://www.djcxy.com/p/18022.html

    上一篇: 用Java初始化Map,Hashmap

    下一篇: 如何在迭代时从字典中删除项目?