views:

217

answers:

3

I need to delete a k/v pair from a dictionary in a loop. After getting RuntimeError: dictionary changed size during iteration I pickled the dictionary after deleting the k/v and in one of the outer loops I try to reopen the newly pickled/updated dictionary. However, as many of you will probably know-I get the same error-I think when it reaches the top of the loop. I do not use my dictionary in the outermost loop.

So my question is-does anyone know how to get around this problem? I want to delete a k/V pair from a dictionary and use that resized dictionary on the next iteration of the loop.

to focus the problem and use the solution from Cygil

list=[27,29,23,30,3,5,40]
testDict={}
for x in range(25):
    tempDict={}
    tempDict['xsquared']=x*x
    tempDict['xinverse']=1.0/(x+1.0)
    testDict[(x,x+1)]=tempDict

for item in list:
    print 'the Dictionary now has',len(testDict.keys()), ' keys'
    for key in testDict.keys():
        if key[0]==item:

  del testDict[key]

I am doing this because I have to have some research assistants compare some observations from two data sets that could not be matched because of name variants. The idea is to throw up a name from one data set (say set A) and then based on a key match find all the names attached to that key in the other dataset (set B). One a match has been identified I don't want to show the value from B again to speed things up for them. Because there are 6,000 observations I also don't want them to have to start at the beginning of A each time they get back to work. However, I can fix that by letting them chose to enter the last key from A they worked with. But I really need to reduce B once the match has been identified

+3  A: 

Delete all keys whose value is > 15:

for k in mydict.keys(): # makes a list of the keys and iterate
                        # over the list, not over the dict.
    if mydict[k] > 15:
        del mydict[k]
nosklo
If you want to be absolutely sure, use `mydict.keys()[:]` to copy the list of keys.
S.Lott
@S.Lott: mydict.keys() already generates a list with a copy of keys on python 2.x
nosklo
+6  A: 

Without code, I'm assuming you're writing something like:

for key in dict:
    if check_condition(dict[key]):
       del dict[key]

If so, you can write

for key in list(dict.keys()):
    if key in dict and check_condition(dict[key]):
        del dict[key]

list(dict.keys()) returns a copy of the keys, not a view, which makes it possible to delete from the dictionary (you are iterating through a copy of the keys, not the keys in the dictionary itself, in this case.)

Am I right in assuming since I need to test\review values that I can't do this because I have to access dict[key]['someValue']
PyNEwbie
for key in dict.keys() *does* return a view in py3+. Use list(dict.keys()) instead.
phihag
cygil: I made some significant edits, please rollback and complain to me if you don't like them
phihag
Hi Philhag, it's cool. Obviously I've been lazy and need to bone up on all the new aspects of Python 3.
+1  A: 

Change:

for ansSeries in notmatched:

To:

for ansSeries in notmatched.copy():
Mark Roddy