Test if dict contained in dict

Question:

Testing for equality works fine like this for python dicts:

first  = {"one":"un", "two":"deux", "three":"trois"}
second = {"one":"un", "two":"deux", "three":"trois"}

print(first == second) # Result: True

But now my second dict contains some additional keys I want to ignore:

first  = {"one":"un", "two":"deux", "three":"trois"}
second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}

Is there a simple way to test if the first dict is part of the second dict, with all its keys and values?

EDIT 1:

This question is suspected to be a duplicate of How to test if a dictionary contains certain keys, but I’m interested in testing keys and their values. Just containing the same keys does not make two dicts equal.

EDIT 2:

OK, I got some answers now using four different methods, and proved all of them working. As I need a fast process, I tested each for execution time. I created three identical dicts with 1000 items, keys and values were random strings of length 10. The second and third got some extra key-value pairs, and the last non-extra key of the third got a new value. So, first is a subset of second, but not of third. Using module timeit with 10000 repetitions, I got:

Method                                                      Time [s]   
first.viewitems() <=second.viewitems()                           0.9 
set(first.items()).issubset(second.items())                      7.3
len(set(first.items()) & set(second.items())) == len(first)      8.5
all(first[key] == second.get(key, sentinel) for key in first)    6.0

I guessed the last method is the slowest, but it’s on place 2.
But method 1 beats them all.

Thanks for your answers!

Asked By: sweber

||

Answers:

So, you basically want to check if one dictionary is a subset of another.

first  = {"one":"un", "two":"deux", "three":"trois"}
second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}

def subset_dic(subset, superset):
    return len(set(subset.items()) & set(superset.items())) == len(subset)


print(subset_dic(first, second))

Prints:

True

In case you want to abstract out the subset/superset part:

def subset_dic(dict1, dict2):
    return len(set(dict1.items()) & set(dict2.items())) == len(min((dict1, dict2), key=len))

Note: this will fail to work, if any value is a mutable object. Hence you can add an additional step (convert mutable object to immutable analog) in the function to overcome this limitation.

Answered By: Eli Korvigo
all(k in second and second[k] == v for k, v in first.items())

if you know that none of the values can be None, it will simplify to:

all(second.get(k, None) == v for k, v in first.items())
Answered By: behzad.nouri

You can use a dictionary view:

# Python 2
if first.viewitems() <= second.viewitems():
    # true only if `first` is a subset of `second`

# Python 3
if first.items() <= second.items():
    # true only if `first` is a subset of `second`

Dictionary views are the standard in Python 3, in Python 2 you need to prefix the standard methods with view. They act like sets, and <= tests if one of those is a subset of (or is equal to) another.

Demo in Python 3:

>>> first  = {"one":"un", "two":"deux", "three":"trois"}
>>> second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}
>>> first.items() <= second.items()
True
>>> first['four'] =  'quatre'
>>> first.items() <= second.items()
False

This works for non-hashable values too, as the keys make the key-value pairs unique already. The documentation is a little confusing on this point, but even with mutable values (say, lists) this works:

>>> first_mutable = {'one': ['un', 'een', 'einz'], 'two': ['deux', 'twee', 'zwei']}
>>> second_mutable = {'one': ['un', 'een', 'einz'], 'two': ['deux', 'twee', 'zwei'], 'three': ['trois', 'drie', 'drei']}
>>> first_mutable.items() <= second_mutable.items()
True
>>> first_mutable['one'].append('ichi')
>>> first_mutable.items() <= second_mutable.items()
False

You could also use the all() function with a generator expression; use object() as a sentinel to detect missing values concisely:

sentinel = object()
if all(first[key] == second.get(key, sentinel) for key in first):
    # true only if `first` is a subset of `second`

but this isn’t as readable and expressive as using dictionary views.

Answered By: Martijn Pieters

# Updated Ans:

METHOD-1: Using Dictionary Views:

As Martijn suggested, We can use dictionary views to check this. dict.viewitems() acts as a set. We can perform various set operations on this like intersection, union etc. (Check this link.)

first.viewitems() <= second.viewitems()
True

We check if first is less than equal to second. This evaluating to True means first is a subset of second.

METHOD-2 Using issubset() operation of sets:

(DISCLAIMER: This method has some redundancy and requires all values to be hashable. Method-1 is suggested to be followed to handle all cases. Thanks Martijn for the suggestions.)

Use .items() attribute of a dictionary to get a list of (key,value) tuples and then use issubset() operation of sets.

This will check for both the keys and the equality..

>>> first  = {"one":"un", "two":"deux", "three":"trois"}
>>> second = {"one":"un", "two":"deux", "three":"trois", "foo":"bar"}

>>> set(first.items()).issubset(second.items())
True
Answered By: Rahul Gupta
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.