测试dict中是否包含dict

时间:2015-06-13 12:30:36

标签: python dictionary

对于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"}

有没有一种简单的方法来测试第一个字典是否是第二个字典的一部分,包括它的所有键和值?

编辑1:

此问题被怀疑与How to test if a dictionary contains certain keys重复,但我对测试密钥及其值感兴趣。只包含相同的键不会使两个dicts相等。

编辑2:

好的,我现在用四种不同的方法得到了一些答案,证明了所有这些方法都有效。由于我需要一个快速的过程,我测试了每个执行时间。我创建了三个相同的词组,包含1000个项目,键和值是长度为10的随机字符串。secondthird获得了一些额外的键值对,以及{{的最后一个非额外键。 1}}获得了一个新值。因此,thirdfirst的子集,但不是second的子集。使用模块third重复10000次,我得到了:

timeit

我猜测最后一种方法是最慢的,但它位于第2位。 但方法1击败了所有人。

感谢您的回答!

4 个答案:

答案 0 :(得分:54)

您可以使用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。它们就像集合一样,<=测试其中一个是否是(或等于)另一个的子集。

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

这也适用于不可散列的值,因为键使得键值对已经是唯一的。文档在这一点上有点令人困惑,但即使使用可变值(例如,列表),这也有效:

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

您还可以将all() 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`

但这并不像使用字典视图那样具有可读性和表现力。

答案 1 :(得分:7)

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

答案 2 :(得分:4)

因此,您基本上想要检查一个字典是否是另一个字典的子集。

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

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

答案 3 :(得分:2)

#Update Ans:

METHOD-1:使用词典视图:

建议Martijn,我们可以使用字典视图来检查这一点。 dict.viewitems()充当一组。我们可以对此进行各种设置操作,例如交集,并集等。(选中此link。)

first.viewitems() <= second.viewitems()
True

我们检查first是否小于second。评估为True意味着firstsecond.

的子集

METHOD-2使用集合的issubset()操作:

(免责声明:此方法有一些冗余,并且要求所有值都是可清除的。建议遵循方法1来处理所有情况。感谢Martijn提出建议。)

使用字典的.items()属性获取(键,值)元组的列表,然后使用 issubset()集的操作。

这将检查键和相等。

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

>>> set(first.items()).issubset(second.items())
True