检查字典的递归函数是另一个字典的子集

时间:2018-03-22 02:19:17

标签: python dictionary

我想检查字典是否是递归的另一个字典的子集。让我们假设两个字典都有内置类型作为项目。

我已经看到已经有一个很老的帖子Python: Check if one dictionary is a subset of another larger dictionary试图解决类似但不完全的问题...因为那里的所有答案都没有用于我的目的我决定发布我自己的solution在那里,但仍然没有完全完成,下面的函数几乎适用于所有情况,但是当子集具有超集中不存在的值时,它会失败,即:

def is_subset(superset, subset):
    for key, value in superset.items():
        if key not in subset:
            continue

        if isinstance(value, dict):
            if not is_subset(value, subset[key]):
                return False
        elif isinstance(value, str):
            if not subset[key] in value:
                return False
        elif isinstance(value, list):
            if not set(subset[key]) <= set(value):
                return False
        elif isinstance(value, set):
            if not subset[key] <= value:
                return False
        else:
            if not subset[key] == value:
                return False

    return True

superset = {'question': 'mcve', 'metadata': {}}
subset = {'question': 'mcve', 'metadata': {'author': 'BPL'}}

print(is_subset(superset, subset))

该函数返回True但它应返回False。那么,你会如何解决它?

3 个答案:

答案 0 :(得分:2)

您的代码逻辑是颠倒的。请注意如何获取超集中的每个元素,并在它们不在子集中时继续。您要做的是获取子集中的每个元素,并检查它们是否在超集

以下是您的代码的固定版本。

def is_subset(superset, subset):
    for key, value in subset.items():
        if key not in superset:
            return False

        if isinstance(value, dict):
            if not is_subset(superset[key], value):
                return False

        elif isinstance(value, str):
            if value not in superset[key]:
                return False

        elif isinstance(value, list):
            if not set(value) <= set(superset[key]):
                return False
        elif isinstance(value, set):
            if not value <= superset[key]:
                return False

        else:
            if not value == superset[key]:
                return False

    return True

以下是给出正确结果的函数的一些示例。

superset = {'question': 'mcve', 'metadata': {}}
subset = {'question': 'mcve', 'metadata': {'author': 'BPL'}}

is_subset(superset, subset) # False

superset = {'question': 'mcve', 'metadata': {'foo': {'bar': 'baz'}}}
subset = {'metadata': {'foo': {}}}

is_subset(superset, subset) # True

superset = {'question': 'mcve', 'metadata': {'foo': 'bar'}}
subset = {'question': 'mcve', 'metadata': {}, 'baz': 'spam'}

is_subset(superset, subset) # False

答案 1 :(得分:0)

只是一个猜测,但我认为因为超集中'元数据'返回的dic是空的,所以没有if语句返回true,所以你得到最终的True返回。

你可以检查一下dic的长度是否为零。如果一个不是另一个,那么返回false。否则继续您的递归解决方案。

答案 2 :(得分:0)

这里是一个解决方案,也可以正确地递归到列表和集合中。 (我更改了论据的顺序,因为这对我来说更有意义)

def is_subset(subset, superset):
    if isinstance(subset, dict):
        return all(key in superset and is_subset(val, superset[key]) for key, val in subset.items())

    if isinstance(subset, list) or isinstance(subset, set):
        return all(any(is_subset(subitem, superitem) for superitem in superset) for subitem in subset)

    if isinstance(subset, str):
        return subset in superset

    # assume that subset is a plain value if none of the above match
    return subset == superset