6

I have to get rid of all the entries which have negative value. Why is my code not working?

dic = {'aa': 20, 'bb': -10, 'cc': -12}

for i in dic:
    if dic[i] < 0:
        del dic[i]
        
print(dic)

When running this code I get an exception:

RuntimeError: dictionary changed size during iteration

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
prithajnath
  • 2,000
  • 14
  • 17
  • you cannot delete an entry in this loop. You can store them into a list or something else. – MarshalSHI Dec 06 '13 at 07:59
  • But how does that help me in getting rid of those entries from the dictionary? – prithajnath Dec 06 '13 at 08:03
  • I'm voting to close this as duplicate of [How to avoid "RuntimeError: dictionary changed size during iteration" error?](https://stackoverflow.com/questions/11941817/how-to-avoid-runtimeerror-dictionary-changed-size-during-iteration-error) – mkrieger1 Mar 21 '22 at 00:30

5 Answers5

6

You can accomplish this by using dict comprehensions.

dic = {k: v for (k, v) in dic.items() if v >= 0}
Steinar Lima
  • 7,644
  • 2
  • 39
  • 40
  • 2
    +1 but should be `dic.items()` instead of `dic.values()`. Also, there is no need for parentheses around `k` and `v` in `for (k, v) ...`. – pepr Dec 06 '13 at 11:28
4

This should work in Python 2.x - substituting the for loop with

 for i in dic.keys():
   if dic[i]<0:
    del dic[i]

The reason why this doesn't work in Python 3.x is that keys returns an iterator instead of a list-- I found an explanation in https://stackoverflow.com/a/11941855/2314737

Quite a subtle difference--I didn't know that.

So, in Python 3.x you would need to use

for i in list(dic):
Community
  • 1
  • 1
user2314737
  • 27,088
  • 20
  • 102
  • 114
2
delete_list = []
for i in dic:
    if dic[i] < 0:
        delete_list.append(i)
for each in delete_list:
    del dic[each]
MarshalSHI
  • 615
  • 1
  • 8
  • 17
  • welcome. Just cannot delete an item in a list when you run loop of this list. – MarshalSHI Dec 06 '13 at 08:38
  • In my opinion, the user2314737's last line solution with `list(dic)` is cleaner in the readability sense. Also copying the wanted items to another dict as shown by Steinar Lina is nice because it loops only once through the dictionary. I suggest to measure all three solutions to know what is the best :) – pepr Dec 06 '13 at 11:25
2

Using dict.pop():

myDict = {'aa': 20, 'bb': -10, 'cc': -12}
condition = []

for x, y in myDict.items ():
    if y <  0:
        condition.append(x)
        
[myDict.pop(x) for x in condition ]

print(myDict)

gives

{'aa': 20}
Subham
  • 397
  • 1
  • 6
  • 14
0
d = {}
# ...

keys = list(d.keys())

for key in keys:
  if something_is_true:
    del d[key]
shioko
  • 302
  • 3
  • 11