检查两个字典是否不相交

Check if two dictionaries are disjoint

有没有 easier/faster 方法可以找出两个字典是否不相交而不是计算它们的交集?

对于我找到的交集 this answer,因此不相交测试将如下所示:

def dicts_disjoint(a, b):
    keys_a = set(a.keys())
    keys_b = set(b.keys())
    intersection = keys_a & keys_b
    return not len(intersection)

但是我认为这是低效的,因为它总是计算整个路口(没有短路退出)。

有更好的主意吗?

您是否在寻找类似的东西:

def dicts_disjoint(a, b):
    return not any(k in b for k in a)

或者:

def dicts_disjoint(a, b):
    return all(k not in b for k in a)

两者都会短路

编辑为仅显示方法和时间

由于 OP 询问执行此操作的最快方法,我根据(我希望)在我的机器上进行的公平测试对正在讨论的方法进行了排名。目的是查找字典的键是否不相交,并且 dict_keys.isdisjoint() 方法似乎胜过其他集合或列表操作。

但是,正如其他答案中提到的,这将根据相关词典的大小以及它们是否不相交而有很大差异。

这些测试仅适用于大小相等(小)的两个不相交的词典。

最快:dict_keys.isdisjoint()

示例:

{"a": 1, "b": 2, "c": 3 }.keys().isdisjoint({ "d": 4, "e": 5, "f": 6}.keys())

时间:

>>> timeit.timeit('{"a": 1, "b": 2, "c": 3 }.keys().isdisjoint({ "d": 4, "e": 5, "f": 6}.keys())')
0.4637166199972853

第二快:set.isdisjoint()

示例:

set({"a": 1, "b": 2, "c": 3 }.keys()).isdisjoint(set({ "d": 4, "e": 5, "f": 6}.keys()))

时间:

>>> timeit.timeit('set({"a": 1, "b": 2, "c": 3 }.keys()).isdisjoint(set({ "d": 4, "e": 5, "f": 6}.keys()))')
0.774243315012427

第三快:列出 Comp 和 all()

示例:

all(k not in {"a": 1, "b": 2, "c": 3 } for k in { "d": 4, "e": 5, "f": 6})

时间:

>>> timeit.timeit('all(k not in {"a": 1, "b": 2, "c": 3 } for k in { "d": 4, "e": 5, "f": 6})')
0.8577601349970791

第四快:对称差异 (^) 与 not()

示例:

not set({"a": 1, "b": 2, "c": 3 }.keys()) ^ set({ "d": 4, "e": 5, "f": 6}.keys())

时间:

>>> timeit.timeit('not set({"a": 1, "b": 2, "c": 3 }.keys()) ^ set({ "d": 4, "e": 5, "f": 6}.keys())')
0.9617313010094222

不要转换为集合; dict_keys 对象已经支持 isdisjoint.

d1.keys().isdisjoint(d2)

仅使用位运算: 变量

dict1 = {"a":1, "b":2}
dict2 = {"a":4, "c":2}

联盟

dict1.keys() | dict2.keys()
# {'b', 'a', 'c'}

路口

dict1.keys() & dict2.keys()
# {'a'}

不相交

dict1.keys() ^ dict2.keys()
# {'b', 'c'}

然后设置一个条件:

"different" if dict1.keys() ^ dict2.keys() else "equal"

空集() return布尔条件下的“假”