Working dollar
Working dollar

Reputation: 296

Dictionary sized change due to iteration of dict

I am attempting to remove key-value pairs from a dict when a sub-dictionary matches values from another dictionary.

Example set-up:

e = {'a':{'aa':'yes'}, 'b':{'ac':'no'}, 'a':{'aa':'yes'}}
f = {'a':{'aa':'yes'}, 'e':{'ab':'no'}, 'a':{'aa':'yes'}}

for keys, values in e.items():
    for k, v in f.items():
        if values.get('aa') == v.get('aa'):
            e.pop(keys)

RuntimeError: dictionary changed size during iteration

Expected result:

#from
e = {'a':{'aa':'yes'}, 'b':{'ac':'no'}, 'a':{'aa':'yes'}}

#to
e = {'b':{'ac':'no'}}

Upvotes: 1

Views: 57

Answers (3)

Vetsin
Vetsin

Reputation: 2592

As you've been told, you can't modify the length of a thing while you're iterating it. There are a few options here, such as:

Saving a list of what you want to remove, then doing it later:

to_remove = []
for keys, values in e.items():
    for k, v in f.items():
        if values.get('aa') == v.get('aa'):
            to_remove.append(keys)
            
for tr in to_remove:
    e.pop(tr)

Cloning the object, so that what you're iterating does not change but the original object can be modified. This is even more memory expensive than the previous however.

for keys, values in dict(e).items(): # or list(e.items())
    for k, v in f.items():
        if values.get('aa') == v.get('aa'):
            e.pop(keys)

You could also, in your case, simply create a new object:

g = {}
for keys, values in e.items():
    for k, v in f.items():
        if values.get('aa') != v.get('aa'):
            g[keys] = values

Upvotes: 0

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

With single dict comprehension:

e = {k:v for k, v in e.items() if v.items() != f.get(k, {}).items()}

{'b': {'ac': 'no'}}

dict.get(key[, default]) allows you to set the needed(or preferred) default value returned for the key in dict

Upvotes: 3

Bastian Venthur
Bastian Venthur

Reputation: 16590

In general, you should not add or remove items from iterables that you are currently iterating over.

Upvotes: 0

Related Questions