For Python 3+:
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
>>> for k in list(mydict.keys()):
... if mydict[k] == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
The other answers work fine with Python 2 but raise a RuntimeError for Python 3:
RuntimeError: dictionary changed size during iteration.
This happens because mydict.keys() returns an iterator not a list.
As pointed out in comments simply convert mydict.keys() to a list by list(mydict.keys()) and it should work.
For Python 2:
A simple test in the console shows you cannot modify a dictionary while iterating over it:
>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
... if k == 'two':
... del mydict[k]
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
As stated in delnan's answer, deleting entries causes problems when the iterator tries to move onto the next entry. Instead, use the keys() method to get a list of the keys and work with that:
>>> for k in mydict.keys():
... if k == 'two':
... del mydict[k]
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
If you need to delete based on the items value, use the items() method instead:
>>> for k, v in mydict.items():
... if v == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
Answer from Blair on Stack OverflowFor Python 3+:
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
>>> for k in list(mydict.keys()):
... if mydict[k] == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
The other answers work fine with Python 2 but raise a RuntimeError for Python 3:
RuntimeError: dictionary changed size during iteration.
This happens because mydict.keys() returns an iterator not a list.
As pointed out in comments simply convert mydict.keys() to a list by list(mydict.keys()) and it should work.
For Python 2:
A simple test in the console shows you cannot modify a dictionary while iterating over it:
>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
... if k == 'two':
... del mydict[k]
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
As stated in delnan's answer, deleting entries causes problems when the iterator tries to move onto the next entry. Instead, use the keys() method to get a list of the keys and work with that:
>>> for k in mydict.keys():
... if k == 'two':
... del mydict[k]
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
If you need to delete based on the items value, use the items() method instead:
>>> for k, v in mydict.items():
... if v == 3:
... del mydict[k]
>>> mydict
{'four': 4, 'one': 1}
You could also do it in two steps:
remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]
My favorite approach is usually to just make a new dict:
# Python 2.7 and 3.x
mydict = { k:v for k,v in mydict.items() if k!=val }
# before Python 2.7
mydict = dict((k,v) for k,v in mydict.iteritems() if k!=val)
Managing adding/removing items from a dictionary while iterating over it periodically
python - Remove element from dictionary by key while iterating - Stack Overflow
python - Deleting items from a dictionary with a for loop - Stack Overflow
python - Unable to delete a dictionary key while iterating over it in python3: "RuntimeError: dictionary changed size during iteration" - Stack Overflow
When I try to do this I get an error saying that the size of the dict has changed during iteration. Is it possible to achieve this without creating another dict?
Thanks!
Hello Redditors,
I've basically the following question. In another thread I got help with a code, a "timers table" all is working fine, now I have a question related on how to manage the writing/erasing of items on this table (which is actually a dictionary) when it's being iterated over. I did some tests and found out you can't add or remove items to the dictionary while it's being iterated, it'll raise a runtime error.
So right now I'm struggling on how to fix this, some basic ideas I have, and I'd like to know which one you believe is the better one or if there's a built-in function I'm missing.
-
Idea #1: I create a "flag" (boolean true/false). General idea is, if this flag is set as True, no one can write/delete (it signals an iteration is happening), once the flag is set as False, iterations can't happen but the other process is allowed to write/delete - I'd need to have some sort of routine than once a new item is going to be added/removed checks for this flag until it can actually add it to the dictionary.
-
Idea #2: I make some sort of queue, a deletion queue and a addition queue, once iteration is over, I go through the deletion queue and then the addition queue (adding, deleting items), then iteration happens again. But then I think I'll get into the same problem as with the dictionary.
-
Idea #3: Make a copy of the dictionary and iterate over this copy instead of the main one, allowing to always have the main one accessible for write/read. I don't expect the dictionary to have a lot of items, ideally would not have more than 3 - 10 items on any given time.
The code is quite simple, basically all I need to do is to push items to this dict, track time and do something once the time is up. In any given time I should be able to add/remove items to this dictionary.
Here is a version modifying your first example, you will need to "copy" your list to iterate with it and deleting at the same time. After you're iterating with the copied list, you can delete from the original list as necessary.
import copy
qr = [{'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''},
{'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''}]
for i, row in enumerate(copy.deepcopy(qr)):
for key, value in row.items():
if value in {' ', None, ''}:
del qr[i][key]
print(qr)
Other than that, usually you want to create a new list than to delete from the original list. A simple list comprehension will do the trick:
qr = [{k:v for k, v in row.items() if v not in {' ', None, ''}} for row in qr]
print(qr) # same result
Output for both:
[{'A': 'B', 'C': '3', 'P': '343'},
{'A': 'B', 'C': '3', 'P': '343'}]
Your approach (collect keys while iterating, delete afterwards) is correct.
Here's your problem:
qr = query_result
for row in qr:
delete = [] # <--- here
You create a new delete list each time you touch a new row. If any data were left in it from a previous row, it is lost.
Instead, you should create it on the same level (of indentation) as you subsequently use it:
delete = [] # Only once for all rows.
qr = query_result
for row in qr:
# ...
for k in delete:
del data[k]
Due to the fact that Python dictionaries are implemented as hash tables, you shouldn't rely on them having any sort of an order. Key order may change unpredictably (but only after insertion or removal of a key). Thus, it's impossible to predict the next key. Python throws the RuntimeError to be safe, and to prevent people from running into unexpected results.
Python 2's dict.items method returns a copy of key-value pairs, so you can safely iterate over it and delete values you don't need by keys, as @wim suggested in comments. Example:
for k, v in my_dict.items():
if v < threshold_value:
del my_dict[k]
However, Python 3's dict.items returns a view object that reflects all changes made to the dictionary. This is the reason the solution above only works in Python 2. You may convert my_dict.items() to list (tuple etc.) to make it Python 3-compatible.
Another way to approach the problem is to select keys you want to delete and then delete them
keys = [k for k, v in my_dict.items() if v < threshold_value]
for x in keys:
del my_dict[x]
This works in both Python 2 and Python 3.
Dictionaries are unordered. By deleting one key nobody can say, what the next key is. So python in general disallow to add or remove keys from a dictionary, over that is iterated.
Just create a new one:
my_dict = {"blue":1,"red":2,"yellow":3,"green":4}
new_dict = {k:v for k,v in my_dict.iteritems() if v >= threshold_value}
For Python-3-x the easy way is to convert the dict into a list() in the iteration:
mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
for k, v in list(mydict.items()):
if k == 'two':
del(mydict[k])
continue
print(k)
You cannot delete a key-value pair while iterating the dictionary. Instead you can use a dict comprehension
Ex:
mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
print({k:v for k,v in mydict.items() if k != 'two'})
Output:
{'four': 4, 'three': 3, 'one': 1}