我想检查字典是否是递归的另一个字典的子集。让我们假设两个字典都有内置类型作为项目。
我已经看到已经有一个很老的帖子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。那么,你会如何解决它?
答案 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