9

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?

user3426752
  • 415
  • 1
  • 8
  • 17

3 Answers3

12

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}
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • That is very elegant code. Is it generally easier to do set operations on dictionaries whenever it is practical? – user3426752 Nov 16 '15 at 17:29
  • @user3426752, in this case, yes, since sets implement intersection and difference operations. If you want the actual dictionaries of the differences, see my edit. – Mark Tolonen Nov 16 '15 at 17:30
5

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()

jme
  • 19,895
  • 6
  • 41
  • 39
  • Thanks jme. I just saw this. It makes it easier to see the logic of how it works. So you are using the dictionary keys as a set? I didn't know you could do that. Thanks! – user3426752 Nov 16 '15 at 19:22
  • 1
    @user3426752 Yep, see [here](https://docs.python.org/3.5/library/stdtypes.html#dictionary-view-objects) for more on dictionary view objects. To be precise, `enrolled.keys()` returns a "set-like view object", which behaves like an immutable set. When you write `set(enrolled)`, a new `set` is created by iterating over the keys of `enrolled` and copying them into a new data structure. `enrolled.keys()` is more efficient, as it does not copy the keys (though it's probably negligible for moderately-sized data). Furthermore, it automatically reflects changes in the keys of the dictionary. – jme Nov 16 '15 at 19:31
2

You can use a lambda as the first argument to filter.

print "Intersection: ", filter(lambda x:x not in participation, enrollments)
Morgan Thrapp
  • 9,748
  • 3
  • 46
  • 67
  • I am not sure I understand. This code looks like it would get me the people that participated but didn't enroll. I think what I am looking for is the people that enrolled but did not participate. Perhaps I have not stated the question clearly? Or I am misunderstanding your answer? Perhaps I am looking for ```print "Difference: ", filter(lambda x:x not in participation, enrollments.keys())``` Would that get me the people that enrolled but did not participate? – user3426752 Nov 16 '15 at 17:25
  • @user3426752 I updated my answer to get you what you need. – Morgan Thrapp Nov 16 '15 at 17:27
  • Thanks, Morgan. That is really helpful. The lambda functions are new to me but I will start reading the documentation on them now. – user3426752 Nov 16 '15 at 17:38
  • @user3426752 They aren't something that get used super often, but it's definitely a good thing to know about. I'm glad I could help! – Morgan Thrapp Nov 16 '15 at 17:39