Reputation: 75
Is it possible to iterate through a dictionary while updating a separate dictionary? I tried to create a copy of my original dictionary and edit that one but I'm still getting an error
d = {30:3, 54:5, 16:2}
r = d
for k,v in d.items():
biggest = max(d,key = d.get)
del(r[biggest])
I need to find the largest value of the dictionary each time it loops through. Then I need to remove that item from the dictionary so I can find the next largest item.
The error I get when I run this code is as follows.
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
for k,v in d.items():
RuntimeError: dictionary changed size during iteration
Upvotes: 2
Views: 1004
Reputation: 12214
You are actually iterating over the same dictionary since r = d
does not creates a new dictionary. r
is just another reference to the same dictionary. You can check the object identities to confirm that:
>>> r = d
>>> r is d
True
Please, see this discussion for more details about object identity:
"is" operator behaves unexpectedly with integers
So, the right thing to do is first create a copy of the dictionary and then alter it:
>>> r = d.copy()
>>> r is d
False
And the iteration:
for k,v in d.items():
biggest = max(d,key = d.get)
del(r[biggest])
So, from your code we just need to change a single line:
d = {30:3, 54:5, 16:2}
r = d.copy() # changed: use copy here
for k,v in d.items():
biggest = max(d,key = d.get)
del(r[biggest])
Upvotes: 1
Reputation: 2349
The problem is that when you use =
in the line r = d
, then r
is not a new object. It is the same d
. I mean they are refer to a single dictionary:
>>> x = {'a':1, 'b':2}
>>> y = x
>>> x
{'a': 1, 'b': 2}
>>> y
{'a': 1, 'b': 2}
>>> x is y
True
So if you change one of them, the other will change too:
>>> y['c']=3
>>> y
{'a': 1, 'c': 3, 'b': 2}
>>> x
{'a': 1, 'c': 3, 'b': 2}
Using id()
method you can check if they are referring to different places in memory or not:
>>> id(y)
44703816L
>>> id(x)
44703816L
>>>
So, you need to use copy()
method instead of =
:
>>> import copy
>>> z = copy.copy(x)
>>> z
{'a': 1, 'c': 3, 'b': 2}
>>> x
{'a': 1, 'c': 3, 'b': 2}
>>> z is x
False
>>>
That cause changing one of them, don't change the other:
>>> z
{'a': 1, 'c': 3, 'b': 2}
>>> x
{'a': 1, 'c': 3, 'b': 2}
>>> z['d']=4
>>> z
{'a': 1, 'c': 3, 'b': 2, 'd': 4}
>>> x
{'a': 1, 'c': 3, 'b': 2}
>>>
Upvotes: 0
Reputation: 132018
As others have pointed out, you cannot change the size of the dictionary while iterating thorough it. It has also been noted by @user312016 that you can iterate over a copy and modify the original.
I am not sure what the intention is, but this code will sort the items from largest value to smallest so you don't have to find the max on each iteration:
d = {30:3, 54:5, 16:2}
d_ = sorted(d.items(), key=lambda x: x[1], reverse=True)
for k, v in d_:
print(k, v)
54, 5
30, 3
16, 2
Upvotes: 0
Reputation: 2174
Iterate on a copy of the dict:
d = {30:3, 54:5, 16:2}
r = d
for k,v in dict(d).items():
biggest = max(d,key = d.get)
del(r[biggest])
Upvotes: 0