By user248237


2011-03-21 23:23:29 8 Comments

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?

10 comments

@glihm 2016-10-10 18:07:02

With python3, iterate on dic.keys() will raise the dictionary size error. You can use this alternative way:

Tested with python3, it works fine and the Error "dictionary changed size during iteration" is not raised:

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

@Michal Charemza 2019-05-24 08:22:01

There is a way that may be suitable if the items you want to delete are always at the "beginning" of the dict iteration

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

The "beginning" is only guaranteed to be consistent for certain Python versions/implementations. For example from What’s New In Python 3.7

the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.

This way avoids a copy of the dict that a lot of the other answers suggest, at least in Python 3.

@Blair 2011-03-21 23:47:28

EDIT:

This answer 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.


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}

@Tim Lesher 2011-09-27 19:01:39

Note that in Python 3, dict.items() returns an iterator (and dict.iteritems() is gone).

@max 2012-01-26 16:55:56

To elaborate on @TimLesher comment... This will NOT work in Python 3.

@Walter Mundt 2012-08-15 17:59:13

To elaborate on @max's elaboration, it will work if you convert the above code with 2to3. One of the default fixers will make the loop look like for k, v in list(mydict.items()): which works fine in Python 3. Same for keys() becoming list(keys()).

@Tomáš Zato - Reinstate Monica 2016-12-18 02:56:40

This doesn't work. I get an error: RuntimeError: dictionary changed size during iteration

@Geoff Crompton 2017-03-22 23:12:29

@TomášZato as Walter pointed out, for python3 you need to use for k in list(mydict.keys()): as python3 makes the keys() method an iterator, and also disallows deleting dict items during iteration. By adding a list() call you turn the keys() iterator into a list. So when you are in the body of the for loop you are no longer iterating over the dictionary itself.

@matanster 2018-09-12 06:11:39

Will list make a copy of the keys, or only point at each of them?

@CodeIt 2019-10-05 14:28:27

@matanster list basically converts an iterator into a list of keys.

@JasonLandbridge 2018-04-05 14:23:29

I tried the above solutions in Python3 but this one seems to be the only one working for me when storing objects in a dict. Basically you make a copy of your dict() and iterate over that while deleting the entries in your original dictionary.

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

@rsanden 2018-01-20 15:25:09

It's cleanest to use 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}

This corresponds to a parallel structure for lists:

>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist):                            # or mylist[:]
...     if k == 'three':
...         mylist.remove(k)
... 
>>> mylist
['one', 'two', 'four']

Both work in python2 and python3.

@AFP_555 2020-02-09 03:46:55

This isn't good in case your dataset is large. This is copying all the objects in memory, right?

@rsanden 2020-02-10 04:27:20

@AFP_555 Yes - my goal here is for clean, parallel, pythonic code. If you need memory efficiency, the best approach I know of is to iterate and build either a list of keys to delete or a new dict of items to save. Beauty is my priority with Python; for large datasets I am using Go or Rust.

@Ignacio Vazquez-Abrams 2011-03-21 23:25:20

Iterate over a copy instead, such as the one returned by items():

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

@jscs 2011-03-22 02:21:41

That doesn't make much sense -- then you can't del v directly, so you've made a copy of each v which you're never going to use and you have to access the items by key anyways. dict.keys() is a better choice.

@Ignacio Vazquez-Abrams 2011-03-22 07:00:41

@Josh: It all depends on how much you're going to need to use v as a criterion for deletion.

@Cecil Curry 2016-02-22 05:37:39

Under Python 3, dict.items() returns an iterator rather than a copy. See commentary for Blair's answer, which (sadly) also assumes Python 2 semantics.

@Aaron 2017-05-19 17:57:08

You can use a dictionary comprehension.

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

@Yehosef 2020-01-13 09:56:02

This is the most Pythonic.

@Aristide 2020-04-15 15:46:12

But it creates a new dictionary instead of modifying d in place.

@Pob 2017-03-02 19:31:06

You could first build a list of keys to delete, and then iterate over that list deleting them.

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]

@kxr 2017-04-28 21:08:27

Its rather a duplicate of @Ritzel's 1st solution (efficient on big dicts w/o full copy). Though a "long read" w/o list comprehension. Yet is it possibly faster nevertheless ?

@Jochen Ritzel 2011-03-22 00:04:25

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)

@Jochen Ritzel 2011-03-22 00:17:17

@senderle: Since 2.7 actually.

@max 2012-01-26 17:28:28

The dict comprehension approach makes a copy of the dictionary; luckily the values at least don't get deep-copied, just linked. Still if you have a lot of keys, it could be bad. For that reason, I like the remove loop approach more.

@AXO 2017-01-16 11:14:12

You can also combine the steps: for k in [k for k in mydict if k == val]: del mydict[k]

@kxr 2017-04-28 21:05:49

the first solution is the only efficient one on big dicts in this thread so far - as it doesn't make a full length copy.

@user395760 2011-03-21 23:28:01

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.

@Nils Lindemann 2016-02-29 16:42:24

You can't modify a collection while iterating it. this is just correct for dicts and friends, but you can modify lists during iteration: L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]

@user395760 2016-02-29 17:19:16

@Nils It doesn't throw an exception but it's still incorrect. Observe: codepad.org/Yz7rjDVT -- see e.g. stackoverflow.com/q/6260089/395760 for an explanation

@Nils Lindemann 2016-02-29 19:20:47

Got me here. Still can't is correct only for dict and friends, while it should be shouldn't for lists.

Related Questions

Sponsored Content

42 Answered Questions

[SOLVED] How do I efficiently iterate over each entry in a Java Map?

22 Answered Questions

[SOLVED] How to iterate over rows in a DataFrame in Pandas?

45 Answered Questions

[SOLVED] How do I merge two dictionaries in a single expression in Python?

29 Answered Questions

[SOLVED] What is the best way to iterate over a dictionary?

  • 2008-09-26 18:20:06
  • Jake Stewart
  • 1606464 View
  • 2625 Score
  • 29 Answer
  • Tags:   c# dictionary loops

12 Answered Questions

[SOLVED] How to remove a key from a Python dictionary?

26 Answered Questions

[SOLVED] How to remove items from a list while iterating?

  • 2009-07-30 15:36:42
  • lfaraone
  • 510747 View
  • 934 Score
  • 26 Answer
  • Tags:   python iteration

11 Answered Questions

[SOLVED] Iterating over dictionaries using 'for' loops

34 Answered Questions

[SOLVED] How do I sort a dictionary by value?

18 Answered Questions

15 Answered Questions

[SOLVED] Delete an element from a dictionary

  • 2011-04-30 21:20:57
  • richzilla
  • 1602807 View
  • 1390 Score
  • 15 Answer
  • Tags:   python dictionary del

Sponsored Content