How to avoid "RuntimeError: dictionary changed size during iteration" error?

PythonListDictionaryLoops

Python Problem Overview


I have checked all of the other questions with the same error yet found no helpful solution =/

I have a dictionary of lists:

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

in which some of the values are empty. At the end of creating these lists, I want to remove these empty lists before returning my dictionary. Current I am attempting to do this as follows:

for i in d:
    if not d[i]:
        d.pop(i)

however, this is giving me the runtime error. I am aware that you cannot add/remove elements in a dictionary while iterating through it...what would be a way around this then?

Python Solutions


Solution 1 - Python

In Python 3.x and 2.x you can use use list to force a copy of the keys to be made:

for i in list(d):

In Python 2.x calling keys made a copy of the keys that you could iterate over while modifying the dict:

for i in d.keys():

But note that in Python 3.x this second method doesn't help with your error because keys returns an a view object instead of copynig the keys into a list.

Solution 2 - Python

You only need to use copy:

This way you iterate over the original dictionary fields and on the fly can change the desired dict d. It works on each Python version, so it's more clear.

In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

In [2]: for i in d.copy():
   ...:     if not d[i]:
   ...:         d.pop(i)
   ...:         

In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}

(BTW - Generally to iterate over copy of your data structure, instead of using .copy for dictionaries or slicing [:] for lists, you can use import copy -> copy.copy (for shallow copy which is equivalent to copy that is supported by dictionaries or slicing [:] that is supported by lists) or copy.deepcopy on your data structure.)

Solution 3 - Python

Just use dictionary comprehension to copy the relevant items into a new dict:

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = {k: v for k, v in d.items() if v}
>>> d
{'a': [1], 'b': [1, 2]}

For this in Python 2:

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = {k: v for k, v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}

Solution 4 - Python

This worked for me:

d = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(d.items()):
    if (value == ''):
        del d[key]
print(d)
# {1: 'a', 3: 'b', 6: 'c'}

Casting the dictionary items to list creates a list of its items, so you can iterate over it and avoid the RuntimeError.

Solution 5 - Python

I would try to avoid inserting empty lists in the first place, but, would generally use:

d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty

If prior to 2.7:

d = dict( (k, v) for k,v in d.iteritems() if v )

or just:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]

Solution 6 - Python

For Python 3:

{k:v for k,v in d.items() if v}

Solution 7 - Python

to avoid "dictionary changed size during iteration error".

for example : "when you try to delete some key" ,

just use 'list' with '.items()' , and here is a simple example :

my_dict = {
    'k1':1,
    'k2':2,
    'k3':3,
    'k4':4
 
    }
    
print(my_dict)

for key, val in list(my_dict.items()):
    if val == 2 or val == 4:
        my_dict.pop(key)

print(my_dict)

+++ output :

{'k1': 1, 'k2': 2, 'k3': 3, 'k4': 4}

{'k1': 1, 'k3': 3}

+++

this is just example and change it based on your case/requirements, i hope this helpful.

Solution 8 - Python

You cannot iterate through a dictionary while its changing during for loop. Make a casting to list and iterate over that list, it works for me.

    for key in list(d):
        if not d[key]: 
            d.pop(key)

Solution 9 - Python

Python 3 does not allow deletion while iterating (using for loop above) dictionary. There are various alternatives to do; one simple way is the to change following line

for i in x.keys():

With

for i in list(x)

Solution 10 - Python

The reason for the runtime error is that you cannot iterate through a data structure while its structure is changing during iteration.

One way to achieve what you are looking for is to use list to append the keys you want to remove and then use pop function on dictionary to remove the identified key while iterating through the list.

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
pop_list = []

for i in d:
        if not d[i]:
                pop_list.append(i)

for x in pop_list:
        d.pop(x)
print (d)

Solution 11 - Python

dictc={"stName":"asas"}
keys=dictc.keys()
for key in list(keys):
    dictc[key.upper()] ='New value'
print(str(dictc))

Solution 12 - Python

For situations like this, i like to make a deep copy and loop through that copy while modifying the original dict.

If the lookup field is within a list, you can enumerate in the for loop of the list and then specify the position as index to access the field in the original dict.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1530318View Question on Stackoverflow
Solution 1 - PythonMark ByersView Answer on Stackoverflow
Solution 2 - PythonAlon ElhararView Answer on Stackoverflow
Solution 3 - PythonMaria ZverinaView Answer on Stackoverflow
Solution 4 - PythonsingriumView Answer on Stackoverflow
Solution 5 - PythonJon ClementsView Answer on Stackoverflow
Solution 6 - PythonucyoView Answer on Stackoverflow
Solution 7 - PythonK.AView Answer on Stackoverflow
Solution 8 - PythonAlvaro Romero DiazView Answer on Stackoverflow
Solution 9 - PythonHasham BeygView Answer on Stackoverflow
Solution 10 - PythonRohitView Answer on Stackoverflow
Solution 11 - Pythonvaibhav.patilView Answer on Stackoverflow
Solution 12 - PythonAjayi Oluwaseun EmmanuelView Answer on Stackoverflow