How to check if one dictionary is a subset of another larger dictionary?
I'm trying to write a custom filter method that takes an arbitrary number of kwargs and returns a list containing the elements of a database-like list that contain those kwargs.
For example, suppose d1 = {'a':'2', 'b':'3'}
and d2
= the same thing. d1 == d2
results in True. But suppose d2
= the same thing plus a bunch of other things. My method needs to be able to tell if d1 in d2, but Python can't do that with dictionaries.
Context:
I have a Word class, and each object has properties like word
, definition
, part_of_speech
, and so on. I want to be able to call a filter method on the main list of these words, like Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
. I can't figure out how to manage these keys and values at the same time. But this could have larger functionality outside this context for other people.
Solution 1:
In Python 3, you can use dict.items()
to get a set-like view of the dict items. You can then use the <=
operator to test if one view is a "subset" of the other:
d1.items() <= d2.items()
In Python 2.7, use the dict.viewitems()
to do the same:
d1.viewitems() <= d2.viewitems()
In Python 2.6 and below you will need a different solution, such as using all()
:
all(key in d2 and d2[key] == d1[key] for key in d1)
Solution 2:
Convert to item pairs and check for containment.
all(item in superset.items() for item in subset.items())
Optimization is left as an exercise for the reader.
Solution 3:
Note for people that need this for unit testing: there's also an assertDictContainsSubset()
method in Python's TestCase
class.
http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
It's however deprecated in 3.2, not sure why, maybe there's a replacement for it.
Solution 4:
For completeness, you can also do this:
def is_subdict(small, big):
return dict(big, **small) == big
However, I make no claims whatsoever concerning speed (or lack thereof) or readability (or lack thereof).
Update: As pointed out by Boris' comment, this trick does not work if your small dict has non-string keys and you're using Python >= 3 (or in other words: in the face of arbitrarily typed keys, it only works in legacy Python 2.x).
If you are using Python 3.9 or newer, though, you can make it work both with non-string typed keys as well as get an even neater syntax.
Provided your code already has both dictionaries as variables, it's very concise to check for this inline:
if big | small == big:
# do something
Otherwise, or if you prefer a reusable function as above, you can use this:
def is_subdict(small, big):
return big | small == big
The working principle is the same as the first function, only this time around making use of the union operator that was extended to support dicts.