测试di中是否包含dict

2024-03-28 20:04:48 发布

您现在位置:Python中文网/ 问答频道 /正文

对于python dicts来说,平等性测试的工作原理如下:

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

print(first == second) # Result: True

但现在我的第二个dict包含了一些我想忽略的额外键:

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

有没有一种简单的方法来测试第一个dict是否是第二个dict的一部分,以及它的所有键和值?

编辑1:

这个问题被怀疑是How to test if a dictionary contains certain keys的重复,但我对测试键及其值感兴趣。仅仅包含相同的键并不能使两个dict相等。

编辑2:

好吧,我现在用四种不同的方法得到了一些答案,并证明了它们都是有效的。由于我需要一个快速的过程,我测试了每个进程的执行时间。我用1000个条目创建了三个相同的dict,键和值是长度为10的随机字符串。secondthird得到了一些额外的键值对,而third的最后一个非额外的键得到了一个新的值。因此,firstsecond的子集,而不是third的子集。使用模块timeit,重复10000次,我得到:

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

我猜最后一种方法是最慢的,但在第二个地方。 但方法一胜过一切。

谢谢你的回答!


Tags: 方法key编辑itemsonedictunfirst
3条回答

您可以使用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`

字典视图是standard in Python 3,在Python 2中,您需要在标准方法前面加上view。它们的行为类似于集合,并且<=测试其中一个是否是另一个集合的子集(或等于)。

Python3中的演示:

>>> 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

这也适用于不可散列值,因为键使键值对已经是唯一的。文档在这一点上有点混乱,但即使使用可变值(比如列表),也可以:

>>> 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

您还可以将^{} function与生成器表达式一起使用;使用object()作为哨兵来简明地检测丢失的值:

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

但这并不像使用字典视图那样可读和表达能力强。

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())

所以,你基本上想检查一个字典是否是另一个字典的子集。

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))

印刷品:

True

如果要抽象出子集/超集部分:

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

注意:如果任何值是可变对象,则此操作将失败。因此,您可以在函数中添加一个额外的步骤(将可变对象转换为可变模拟)来克服此限制。

相关问题 更多 >