Reputation: 3388
Is there an easier/faster way to find out if two dictionaries are disjoint than calculating their intersection?
For the intersection I found this answer, so the disjoint-test would look like this:
def dicts_disjoint(a, b):
keys_a = set(a.keys())
keys_b = set(b.keys())
intersection = keys_a & keys_b
return not len(intersection)
However I think this is inefficient since it always calculates the whole intersection (no short-circuit quit).
Any better ideas?
Upvotes: 3
Views: 2072
Reputation: 1130
Using only bit operation: variables
dict1 = {"a":1, "b":2}
dict2 = {"a":4, "c":2}
union
dict1.keys() | dict2.keys()
# {'b', 'a', 'c'}
intersection
dict1.keys() & dict2.keys()
# {'a'}
disjoint
dict1.keys() ^ dict2.keys()
# {'b', 'c'}
Then set a condition:
"different" if dict1.keys() ^ dict2.keys() else "equal"
An empty set() return "False" in boolean conditions
Upvotes: 1
Reputation: 1738
Edited to display methods and timings only
Since the OP asked about the fastest method to perform this operation, I've ranked the ones under discussion according to a (I hope) fair test on my machine. The aim is to find if the keys of a dictionary are disjoint, and it seems the dict_keys.isdisjoint()
method wins out over other set or list operations.
However, as mentioned in other answers, this will vary considerably depending on the size of the relative dictionaries and whether or not they are disjoint.
These tests are only for two disjoint dictionaries of equal (small) size.
Fastest: dict_keys.isdisjoint()
Example:
{"a": 1, "b": 2, "c": 3 }.keys().isdisjoint({ "d": 4, "e": 5, "f": 6}.keys())
Timing:
>>> timeit.timeit('{"a": 1, "b": 2, "c": 3 }.keys().isdisjoint({ "d": 4, "e": 5, "f": 6}.keys())')
0.4637166199972853
Second Fastest: set.isdisjoint()
Example:
set({"a": 1, "b": 2, "c": 3 }.keys()).isdisjoint(set({ "d": 4, "e": 5, "f": 6}.keys()))
Timing:
>>> timeit.timeit('set({"a": 1, "b": 2, "c": 3 }.keys()).isdisjoint(set({ "d": 4, "e": 5, "f": 6}.keys()))')
0.774243315012427
Third Fastest: List Comp and all()
:
Example:
all(k not in {"a": 1, "b": 2, "c": 3 } for k in { "d": 4, "e": 5, "f": 6})
Timing:
>>> timeit.timeit('all(k not in {"a": 1, "b": 2, "c": 3 } for k in { "d": 4, "e": 5, "f": 6})')
0.8577601349970791
Fourth Fastest: Symmetric Difference (^
) with not()
Example:
not set({"a": 1, "b": 2, "c": 3 }.keys()) ^ set({ "d": 4, "e": 5, "f": 6}.keys())
Timing:
>>> timeit.timeit('not set({"a": 1, "b": 2, "c": 3 }.keys()) ^ set({ "d": 4, "e": 5, "f": 6}.keys())')
0.9617313010094222
Upvotes: 4
Reputation: 60147
Don't convert to a set; a dict_keys
object already supports isdisjoint
.
d1.keys().isdisjoint(d2)
Upvotes: 10
Reputation: 30258
Are you looking for something like:
def dicts_disjoint(a, b):
return not any(k in b for k in a)
Or:
def dicts_disjoint(a, b):
return all(k not in b for k in a)
Both will short-circuit.
Upvotes: 4