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!
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.
all(k in second and second[k] == v for k, v in first.items())
如果你知道没有任何值可以是None
,它将简化为:
all(second.get(k, None) == v for k, v in first.items())
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.
# 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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.