How to resize dictionary during iteration in Python

I want to pull out all the big values โ€‹โ€‹and its keys in the dictionary and save the least. Here is a part of my program

for key,value in dictionary.items(): for key1, value1 in dictionary.items(): if key1!= key and value > value1: dictionary.pop(key) print (dictionary) 

The result is

 RuntimeError: dictionary changed size during iteration 

How to avoid this error?

+8
python dictionary
source share
7 answers

Alternative solutions

If you are looking for the smallest value in a dictionary, you can do this:

 min(dictionary.values()) 

If you cannot use min, you can use sorted:

 sorted(dictionary.values())[0] 

Why am I getting this error?

On the other hand, the reason you are experiencing a Runtime Error is because in the inner loop you are modifying the iterator that your outer loop is based on. When you pop record that has not yet been reached by the external loop, and the external iterator reaches it, it tries to access the remote element, thereby causing an error.
If you try to execute your Python 2.7 code (instead of 3.x), you will get, in essence, Key Error .

What can I do to avoid a mistake?

If you want to change the iterability within the loop based on your iterator, you should use a deep copy .

+6
source share

You can use copy.deepcopy to make a copy of the original dict, drag the copy by changing the original.

 from copy import deepcopy d=dict() for i in range(5): d[i]=str(i) k=deepcopy(d) d[2]="22" print(k[2]) #The result will be 2. 

Your problem is to iterate over what you are changing.

+5
source share

In Python3, Try

 for key in list(dict.keys()): if condition: matched del dict[key] 

One more thing to be careful about when dict is cyclized in order to update its key:

Code1:

 keyPrefix = 'keyA' for key, value in Dict.items(): newkey = '/'.join([keyPrefix, key]) Dict[newkey] = Dict.pop(key) 

Codex2:

 keyPrefix = 'keyA' for key, value in Dict.keys(): newkey = '/'.join([keyPrefix, key]) Dict[newkey] = Dict.pop(key) 

The result of code 1 / code2 is:

 {'keyA/keyA/keyB' : ", 'keyA/keyA/keyA': "} 

My way to solve this unexpected result:

  Dict = {'/'.join([keyPrefix, key]): value for key, value in Dict.items()} 

Link: https://hanbaobao2005.wordpress.com/2016/07/21/loop-a-dict-to-update-key/

+4
source share

Write the key during the loop, and then execute dictionary.pop (key) when the loop is complete. Like this:

 for key,value in dictionary.items(): for key1, value1 in dictionary.items(): if key1!= key and value > value1: storedvalue = key dictionary.pop(key) 
+2
source share

Here is one way to solve it:

  • From the dictionary, get a list of keys sorted by value
  • Since the first key in this list has the least value, you can do whatever you want with it.

Here is an example:

 # A list of grades, not in any order grades = dict(John=95,Amanda=89,Jake=91,Betty=97) # students is a list of students, sorted from lowest to highest grade students = sorted(grades, key=lambda k: grades[k]) print 'Grades from lowest to highest:' for student in students: print '{0} {1}'.format(grades[student], student) lowest_student = students[0] highest_student = students[-1] print 'Lowest grade of {0} belongs to {1}'.format(grades[lowest_student], lowest_student) print 'Highest grade of {0} belongs to {1}'.format(grades[highest_student], highest_student) 

The secret sauce here is in the sorted () function: instead of sorting by keys, we sorted by values.

+1
source share

Since I'm reading your loop right now, you want to save only one small element, but without using min . So do the opposite of what your code is doing now, check if value1 < minValueSoFar , if so, save key1 as minKeySoFar. Then at the end of the loop (as Zayatz suggested), do dictionary.pop(minKeySoFar)

As an aside, I note that the key1!=key test is irrelevant and computationally inefficient, assuming a fairly long list.

 minValueSoFar = 9999999; # or whatever for key,value in dictionary.items(): if value < minValueSoFar: minValueSoFar = value minKeySoFar = key dictionary.pop(minKeySoFar) # or whatever else you want to do with the result 
0
source share

If you just want to save the key with the smallest value, I would do this by first finding this element and then creating a new dictionary containing only it. If your dictionary was d , something like this will do on one line:

 d = dict((min(d.items(), key=lambda item: item[1]),)) 

This will not only eliminate problems with updating the dictionary when it is repeated, but probably faster than deleting all other elements.

If for some reason you make changes in place, the following will work because it makes a copy of all the keys before changing the dictionary:

 key_to_keep = min(d.items(), key=lambda item: item[1])[0] for key in list(d): if key != key_to_keep: d.pop(key) 
0
source share

All Articles