2

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
AKS
  • 18,983
  • 3
  • 43
  • 54
DakotaDickey44
  • 75
  • 1
  • 2
  • 7
  • 2
    What's the purpose behind this? In the end it would lead to just an empty dictionary... – Jan Köhler Apr 26 '16 at 04:42
  • Have you ever tried to build something and you know how long each type of board you will be using needs to be. The problem is, because lumber comes in 8 foot pieces you will always have leftover, lumber that is too short to do anything with. This can cause you to buy too few boards. This program will take into consideration all these factors and tell you how many boards you will need to buy. – DakotaDickey44 Apr 26 '16 at 04:57

4 Answers4

1

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])
marcospereira
  • 12,045
  • 3
  • 46
  • 52
0

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])
Pierre Barre
  • 2,174
  • 1
  • 11
  • 23
0

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}
>>> 
EbraHim
  • 2,279
  • 2
  • 16
  • 28
0

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
sberry
  • 128,281
  • 18
  • 138
  • 165