Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test if dict contained in dict

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!

like image 439
sweber Avatar asked Jun 13 '15 12:06

sweber


People also ask

Can a dict contain a dict?

Keys of a Dictionary must be unique and of immutable data type such as Strings, Integers and tuples, but the key-values can be repeated and be of any type. Nested Dictionary: Nesting Dictionary means putting a dictionary inside another dictionary.

How do you know if a dictionary is subset of another?

Method #1 : Using all() + items() This task can be performed using the combination of above two functions, in which we check for all the items of the subdict with the original dict using all() and fetch it's each pair using items() .

How do you check if a value is present in a dictionary in Python?

Check if a value exists in a dictionary: in operator, values() To check if a value exists in a dictionary, i.e., if a dictionary has/contains a value, use the in operator and the values() method. Use not in to check if a value does not exist in a dictionary.


2 Answers

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.

like image 71
Martijn Pieters Avatar answered Oct 18 '22 12:10

Martijn Pieters


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()) 
like image 23
behzad.nouri Avatar answered Oct 18 '22 11:10

behzad.nouri