Iterating over an `OrderedDict` and deleting some of its keys? [duplicate] - python

This question already has an answer here:
deleting entries in a dictionary based on a condition
(1 answer)
Closed 6 years ago.
Suppose I have an OrderedDict od with integer keys and integer values. I want to iterate over od and delete elements of od based on the value I find. Basically what I want to achieve is:
od = {1: 2, 2: 4, 3: 5}
for key in od:
del od[key]
In the end I want od to be equal to {1: 2, 3: 5}. Python does not allow to change the size of an OrderedDict during its iteration. Is it possible to overcome this problem?
I am working with Python 3.5

That is because you can not modify the length of dict while you are iterating over it. Instead you have to iterate over the copy of list of keys within the dict as:
# For both Python 3.x and 2.7
>>> for key in list(od):
... del od[key]
...
>>> od
{}
However in Python2.7, one may even use dict.keys() to get the same behavior:
# In Python 2.7
>>> for key in od.keys():
... del od[key]
...
>>> od
{}

this is the easiest way i know. enjoy!
With dicts, you can't change the length of the dictionary. however, what you can do is make a list copy of the original dictionary and use that to iterate through the original dictionary. as shown below
od = {'a': 2, 'b': 4, 'c': 5}
for key in list(od):
if key == 'b':
print(key)
del od[key]
print(od)

I think this what you mean to do
od = {1: 2, 2: 4, 3: 5}
for key in od.copy(): # iterate over a copy
if key in od and od[key] in od: # check for both key, 'target' key
del od[od[key]] # then delete the target with indirect indexing
od
Out[52]: {1: 2, 3: 5}

Related

Is there a possible way to delete an item using position in the dictionary in Python?

so I ran into this problem. Let's say I have a dictionary, and I want to delete the last item without knowing the item's key name. How would I do so?
You could probably use popitem()
(from Python 3.5+ for OrderedDict, 3.7+ for all dictionaries):
d = {'a':1, 'b':2,'c':3}
d.popitem() # ('c',3)
print(d)
{'a': 1, 'b': 2}
popitem() works like a LIFO queue (stack) so it removes the last added key. To delete the first item, you can use popitem(False) which works like a FIFO queue.
To delete some other arbitrary position, you can use itertools.islice to help:
from itertools import islice
d = {'a':1, 'b':2,'c':3,'d':4,'e':5}
del d[next(islice(d,2,None))] # delete at index 2
print(d)
{'a': 1, 'b': 2, 'd': 4, 'e': 5}
This still needs to run through keys sequentially but at least it doesn't create an intermediate data structure (list) to do so.
You pop the last item like this:
dictionary = {'a': 2, 'd': 3}
last_key = list(dictionary)[-1]
dictionary.pop(last_key)
print(dictionary)
Output
{'a': 2}
From Python3.7 dicts keep the order of keys. So, list(dictionary) represents keys in their insertion order

Is it possible to iterate through all of a dictionary's keys except a specific subset?

Let's say I have a dictionary with the keys being all the numbers 1-10. And I want to iterate through that excluding keys 6-8. Is it possible to do something like
for key in dictionary.keys().exclude([1,2,3])
I've made up .exclude() to demonstrate what I want to do.
Remember that the keys of a dictionary are unique, so using set operations would be suitable (and are very performant):
dictionary = {i: i for i in range(1, 11, 1)}
for key in set(dictionary) - set([1, 2, 3]):
print(key)
You can also use a set literal instead of an explicit set conversion like this:
for key in set(dictionary) - {1, 2, 3}:
print(key)
And, as pointed out in the comments, dictionary.keys() as you originally had it would behave in the same way as set(dictionary).
for key in [k for k in dictionary.keys() if k not in [1,2,3]]:
... do something
A technique to bypass a few iterations from a loop would be to use continue.
dictionary = {1: 1, 2: 2, 3 : 3, 4: 4}
for key in dictionary:
if key in {1, 2, 3}:
continue
print(key)

Python how to update a dictionary with another dictionary by applying add to existing values

I have an existing dictionary with string keys and numerical values. I create another dictionary containing new keys and values which I need to update over the existing dictionary.
Only requirement is I need that if a key in new dictionary already exists in target dictionary, the value is added to existing value, instead of replacing it.
How can I achieve this in Python 2.7?
Looks like a good case to use Counter from collections:
>>> from collections import Counter
>>> d1 = Counter({'a':1,'b':1})
>>> d2 = Counter({'a':2,'c':3})
>>> d1.update(d2)
>>> d1
Counter({'a': 3, 'c': 3, 'b': 1})
You also can create new collection:
>>> d1 + d2
Counter({'a': 3, 'c': 3, 'b': 1})

How do I find the keys in one dictionary that do not have a counterpart in another dictionary?

In Python, how do I find the keys in one dictionary that do not have a counterpart in another dictionary? The practical problem is that I have a dictionary of people that enrolled and a dictionary with their daily participation and I am trying to find the people that enrolled but did not participate, or are in the enrollments dictionary and not in the participation dictionary.
In the Python cookbook I found good code for the intersection enrollments and participation, or the intersection of the two dictionaries:
print "Intersection: ", filter(enrollments.has_key, participation.keys())
But I can't figure out how to extend this logic to the obverse (?) case. I have tried putting a not in front of participation.keys() but I get an error. Is there a way to extend the logic in the filter to my problem or another way to approach it altogether?
Use sets on the keys to find the difference:
>>> P = dict(zip('a b c d'.split(),[1,2,3,4]))
>>> E = dict(zip('a b e f'.split(),[6,7,8,9]))
>>> set(P)-set(E)
{'d', 'c'}
>>> set(E)-set(P)
{'f', 'e'}
Also, you can use a dictionary comprehension. It is a way to map a function across a dictionary, and/or filter the contents. The syntax means to return the key:value pair for each key and value in the dictionary's items where the key is not in another dictionary:
>>> {k:v for k,v in P.items() if k not in E}
{'d': 4, 'c': 3}
>>> {k:v for k,v in E.items() if k not in P}
{'f': 9, 'e': 8}
In Python 3, dict.keys() gives you a set-like view of the keys in a dictionary, so doing this is as simple as:
>>> enrolled = {'steve': 0, 'mike': 42, 'judy': 100}
>>> participated = {'judy': 5, 'mike': 10}
>>> enrolled.keys() - participated.keys()
{'steve'}
In Python 2, replace .keys() with .viewkeys()
You can use a lambda as the first argument to filter.
print "Intersection: ", filter(lambda x:x not in participation, enrollments)

How to iterate over a dynamic object?

I have some code that iterates over the values of a dictionary. If the value meets certain conditions, it is deleted from the dictionary. Those conditions are contingent on the existence of other values in the dictionary. This is why I don't want to just copy the old dictionary and make deletions, then re-attribute it.
When I try to run it, I get an error that the size of the dictionary changed while iterating it.
Is there a way to iterate over a dictionary that allows it to change size, and the existence of keys and values, while it is iterating?
Build a new dictionary which contains the keys you want to keep. This can be done with a dictionary comprehension, or a manual for loop.
Here's a comprehension:
return {k: v for k, v in my_dict.items() if some-condition}
Here's a manual loop:
result = {}
for k, v in my_dict.items():
if some-condition:
result[k] = v
return result
Well, yes you can iterate on by the keys (Python3)! Take a look:
>>> dc
{1: 'aze', 3: 'poi', 4: 'mlk'}
>>> dc = {1:"aze", 2:"qsd", 3:"poi", 4:"mlk"}
>>> dc
{1: 'aze', 2: 'qsd', 3: 'poi', 4: 'mlk'}
>>> keys = list(dc.keys())
>>> keys
[1, 2, 3, 4]
>>> for k in keys:
if "q" in dc[k]:
del dc[k]
>>> dc
{1: 'aze', 3: 'poi', 4: 'mlk'}
>>>
You can iterate over the keys instead of over the dict itself. In the following example, all values that are odd-numbered are removed from the dict:
>>> a = {'a': 12, 'b': 3, 'c': 14}
>>> for key in list(a.keys()):
if a[key] % 2 == 0:
del a[key]
>>> a
{'b': 3}

Categories