关键词:
【中文标题】如何检查一个字典是不是是另一个更大字典的子集?【英文标题】:How to check if one dictionary is a subset of another larger dictionary?如何检查一个字典是否是另一个更大字典的子集? 【发布时间】:2012-03-08 14:05:28 【问题描述】:我正在尝试编写一个自定义过滤器方法,该方法采用任意数量的 kwargs 并返回一个列表,其中包含包含这些 kwargs 的类似数据库的列表的元素>.
例如,假设d1 = 'a':'2', 'b':'3'
和d2
= 相同的东西。 d1 == d2
结果为真。但是假设d2
= 相同的东西加上一堆其他的东西。我的方法需要能够判断 d1 in d2,但 Python 不能用字典做到这一点。
上下文:
我有一个 Word 类,每个对象都有 word
、definition
、part_of_speech
等属性。我希望能够在这些单词的主列表上调用过滤器方法,例如Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
。我不知道如何同时管理这些键和值。但这对于其他人来说可能在此上下文之外具有更大的功能。
【问题讨论】:
my_dict == my_dict | subset_dict
在 Python 3.9+ 上使用 dict union operator。
【参考方案1】:
转换为项目对并检查是否包含。
all(item in superset.items() for item in subset.items())
优化留给读者练习。
【讨论】:
如果 dict 值是可散列的,使用 viewitems() 是我能想到的最优化的方式:d1.viewitems() <= d2.viewitems()
。 Timeit 运行显示出超过 3 倍的性能提升。如果不是可散列的,即使使用 iteritems()
而不是 items()
也会导致大约 1.2 倍的改进。这是使用 Python 2.7 完成的。
我不认为优化应该留给读者 - 我担心人们会真正使用它而没有意识到它会构建 superset.items() 的副本并为每个子集中的项目。
使用 Python 3 items()
将返回轻量级视图而不是副本。无需进一步优化。
嵌套目录呢?
这很有趣。我将把幽默的主题细化留给读者。【参考方案2】:
>>> d1 = 'a':'2', 'b':'3'
>>> d2 = 'a':'2', 'b':'3','c':'4'
>>> all((k in d2 and d2[k]==v) for k,v in d1.iteritems())
True
上下文:
>>> d1 = 'a':'2', 'b':'3'
>>> d2 = 'a':'2', 'b':'3','c':'4'
>>> list(d1.iteritems())
[('a', '2'), ('b', '3')]
>>> [(k,v) for k,v in d1.iteritems()]
[('a', '2'), ('b', '3')]
>>> k,v = ('a','2')
>>> k
'a'
>>> v
'2'
>>> k in d2
True
>>> d2[k]
'2'
>>> k in d2 and d2[k]==v
True
>>> [(k in d2 and d2[k]==v) for k,v in d1.iteritems()]
[True, True]
>>> ((k in d2 and d2[k]==v) for k,v in d1.iteritems())
<generator object <genexpr> at 0x02A9D2B0>
>>> ((k in d2 and d2[k]==v) for k,v in d1.iteritems()).next()
True
>>> all((k in d2 and d2[k]==v) for k,v in d1.iteritems())
True
>>>
【讨论】:
【参考方案3】:对于键和值检查使用:
set(d1.items()).issubset(set(d2.items()))
如果您只需要检查键:
set(d1).issubset(set(d2))
【讨论】:
如果任一字典中的任何值不可散列,则第一个表达式将不起作用。 第二个例子可以通过删除 set(d2) 稍微缩短,因为“issubset 接受任何可迭代”。 docs.python.org/2/library/stdtypes.html#set 这是错误的:d1='a':1,'b':2; d2='a':2,'b':1
-> 第二个 sn-p 将返回 True
...
@FrancescoPasa 第二个 sn-p 明确表示:“如果您只需要检查键”。 'a', 'b'
实际上是 'a', 'b'
的子集;)【参考方案4】:
我的函数出于相同目的,递归地执行此操作:
def dictMatch(patn, real):
"""does real dict match pattern?"""
try:
for pkey, pvalue in patn.iteritems():
if type(pvalue) is dict:
result = dictMatch(pvalue, real[pkey])
assert result
else:
assert real[pkey] == pvalue
result = True
except (AssertionError, KeyError):
result = False
return result
在您的示例中,dictMatch(d1, d2)
应该返回 True,即使 d2 中有其他内容,而且它也适用于较低级别:
d1 = 'a':'2', 'b':3: 'iii'
d2 = 'a':'2', 'b':3: 'iii', 4: 'iv','c':'4'
dictMatch(d1, d2) # True
注意:可能会有更好的解决方案避免if type(pvalue) is dict
子句并适用于更广泛的情况(如哈希列表等)。递归在这里也不受限制,因此使用风险自负。 ;)
【讨论】:
【参考方案5】:需要这个进行单元测试的人请注意:Python 的 TestCase
类中还有一个 assertDictContainsSubset()
方法。
http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
然而,它在 3.2 中已被弃用,不知道为什么,也许有一个替代品。
【讨论】:
很好奇,在what's new in 3.2 中发现了这一点: assertDictContainsSubset() 方法已被弃用,因为它使用错误顺序的参数错误实现。这造成了难以调试的错觉,其中像 TestCase().assertDictContainsSubset('a':1, 'b':2, 'a':1) 这样的测试会失败。 (由雷蒙德·海廷格供稿。) 等等,左边是预期的,右边是实际的......这不应该失败吗?该函数唯一的问题是哪个去哪个地方令人困惑?【参考方案6】:此函数适用于非散列值。我也认为它清晰易读。
def isSubDict(subDict,dictionary):
for key in subDict.keys():
if (not key in dictionary) or (not subDict[key] == dictionary[key]):
return False
return True
In [126]: isSubDict(1:2,3:4)
Out[126]: False
In [127]: isSubDict(1:2,1:2,3:4)
Out[127]: True
In [128]: isSubDict(1:2:3,1:2:3,3:4)
Out[128]: True
In [129]: isSubDict(1:2:3,1:2:4,3:4)
Out[129]: False
【讨论】:
【参考方案7】:为了完整起见,您也可以这样做:
def is_subdict(small, big):
return dict(big, **small) == big
但是,我对速度(或缺乏)或可读性(或缺乏)不做任何声明。
更新:正如鲍里斯的评论所指出的,如果您的小字典有非字符串键并且您使用的是 Python >= 3(或者换句话说:面对任意键入的键,则此技巧不起作用,它仅适用于旧版 Python 2.x)。
不过,如果您使用的是 Python 3.9 或更新版本,您可以让它与非字符串类型的键一起工作,并获得更简洁的语法。
如果您的代码已经将两个字典作为变量,那么检查这个内联非常简洁:
if big | small == big:
# do something
否则,或者如果您更喜欢上述可重用函数,则可以使用:
def is_subdict(small, big):
return big | small == big
工作原理与第一个函数相同,只是这次使用了扩展为支持字典的联合运算符。
【讨论】:
附注:提到small.viewitems() <= big.viewitems()
的其他答案很有希望,但有一个警告:如果您的程序也可以在 Python 2.6(甚至更低版本)上使用,d1.items() <= d2.items()
实际上是在比较 2元组列表,没有特定的顺序,因此最终结果可能不可靠。出于这个原因,我切换到@blubberdiblub 的答案。赞成。
这很酷,但它似乎不适用于嵌套字典。
@FrederikBaetens 这不是故意的。此外,我相信没有普遍接受的方法来做到这一点,因为您可以通过多种方式来解决它,并且您可以对此类字典施加多种可能的结构/限制。以下是一些浮现在脑海中的问题:你如何确定是否应该深入到更深层次的字典?以dict
作为基类的类型的对象呢?如果它没有并且仍然表现得像dict
怎么办?如果small
和big
在匹配键处包含不同类型的值,但仍表现得像dict,该怎么办?
这些是有效的点,但是一个基本的函数可以使用普通的嵌套字典应该很好。我发布了一个示例here,但@NutCracker 的解决方案更好
**big, **small == big
也可以,不需要等到 3.9 !【参考方案8】:
在 Python 3 中,您可以使用 dict.items()
来获取 dict 项的类似集合的视图。然后,您可以使用<=
运算符来测试一个视图是否是另一个视图的“子集”:
d1.items() <= d2.items()
在 Python 2.7 中,使用 dict.viewitems()
执行相同操作:
d1.viewitems() <= d2.viewitems()
在 Python 2.6 及以下版本中,您将需要不同的解决方案,例如使用 all()
:
all(key in d2 and d2[key] == d1[key] for key in d1)
【讨论】:
警告:如果您的程序可能在 Python 2.6(甚至更低版本)上使用,d1.items() <= d2.items()
实际上是在比较 2 个元组列表,没有特定顺序,因此最终结果可能不可靠.出于这个原因,我切换到@blubberdiblub 的答案。
@RayLuo 是的,viewitems 和 items 是不一样的。编辑澄清。
d1.items() <= d2.items()
是未定义的行为。它没有记录在官方文档中,最重要的是,它没有经过测试:github.com/python/cpython/blob/… 所以这取决于实现。
@RodrigoMartins 已记录在 here:“对于类似集合的视图,为抽象基类 collections.abc.Set
定义的所有操作都可用”
@RodrigoMartins 如果您担心未来的维护者,请将操作包装在明确命名的函数中或添加代码注释。将代码标准降低到不称职的开发人员的水平是一个糟糕的主意。【参考方案9】:
这个看似简单的问题花费了我几个小时的研究时间才能找到一个 100% 可靠的解决方案,所以我记录了我在这个答案中发现的内容。
“Pythonic-ally”说,small_dict <= big_dict
将是最直观的方式,但可惜它行不通。 'a': 1 < 'a': 1, 'b': 2
似乎在 Python 2 中有效,但它并不可靠,因为官方文档明确指出了它。去搜索“除平等之外的结果是一致地解决的,但没有另外定义。”在this section。更不用说,比较 Python 3 中的 2 个 dicts 会导致 TypeError 异常。
第二个最直观的事情是 small.viewitems() <= big.viewitems()
仅适用于 Python 2.7,small.items() <= big.items()
适用于 Python 3。但有一个警告:它可能存在错误。如果您的程序可能在 Python d1.items() <= d2.items() 实际上是在比较 2 个元组列表,没有特定的顺序,因此最终结果将是不可靠的,它会成为您程序中的一个讨厌的错误。我并不热衷于为 Python
我与@blubberdiblub 's answer 安定下来(归功于他):
def is_subdict(small, big):
return dict(big, **small) == big
值得指出的是,这个答案依赖于dicts之间的==
行为,这在官方文档中有明确的定义,因此应该适用于每个Python版本。去搜索:
【讨论】:
【参考方案10】:这是给定问题的一般递归解决方案:
import traceback
import unittest
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
class Foo(unittest.TestCase):
def setUp(self):
self.dct =
'a': 'hello world',
'b': 12345,
'c': 1.2345,
'd': [1, 2, 3, 4, 5],
'e': 1, 2, 3, 4, 5,
'f':
'a': 'hello world',
'b': 12345,
'c': 1.2345,
'd': [1, 2, 3, 4, 5],
'e': 1, 2, 3, 4, 5,
'g': False,
'h': None
,
'g': False,
'h': None,
'question': 'mcve',
'metadata':
def tearDown(self):
pass
def check_true(self, superset, subset):
return self.assertEqual(is_subset(superset, subset), True)
def check_false(self, superset, subset):
return self.assertEqual(is_subset(superset, subset), False)
def test_simple_cases(self):
self.check_true(self.dct, 'a': 'hello world')
self.check_true(self.dct, 'b': 12345)
self.check_true(self.dct, 'c': 1.2345)
self.check_true(self.dct, 'd': [1, 2, 3, 4, 5])
self.check_true(self.dct, 'e': 1, 2, 3, 4, 5)
self.check_true(self.dct, 'f':
'a': 'hello world',
'b': 12345,
'c': 1.2345,
'd': [1, 2, 3, 4, 5],
'e': 1, 2, 3, 4, 5,
)
self.check_true(self.dct, 'g': False)
self.check_true(self.dct, 'h': None)
def test_tricky_cases(self):
self.check_true(self.dct, 'a': 'hello')
self.check_true(self.dct, 'd': [1, 2, 3])
self.check_true(self.dct, 'e': 3, 4)
self.check_true(self.dct, 'f':
'a': 'hello world',
'h': None
)
self.check_false(
self.dct, 'question': 'mcve', 'metadata': 'author': 'BPL')
self.check_true(
self.dct, 'question': 'mcve', 'metadata': )
self.check_false(
self.dct, 'question1': 'mcve', 'metadata': )
if __name__ == "__main__":
unittest.main()
注意:原始代码在某些情况下会失败,fixing 的功劳归@olivier-melançon
【讨论】:
代码在if not set(value) <= set(superset[key])
这一行中出现一个超集,该超集嵌套在一个列表中。【参考方案11】:
我知道这个问题很老,但这是我检查一个嵌套字典是否是另一个嵌套字典的一部分的解决方案。解决方案是递归的。
def compare_dicts(a, b):
for key, value in a.items():
if key in b:
if isinstance(a[key], dict):
if not compare_dicts(a[key], b[key]):
return False
elif value != b[key]:
return False
else:
return False
return True
【讨论】:
【参考方案12】:如果您不介意使用pydash
,那么is_match
就是这样做的:
import pydash
a = 1:2, 3:4, 5:6:7
b = 3:4.0, 5:6:8
c = 3:4.0, 5:6:7
pydash.predicates.is_match(a, b) # False
pydash.predicates.is_match(a, c) # True
【讨论】:
【参考方案13】:适用于嵌套字典的简短递归实现:
def compare_dicts(a,b):
if not a: return True
if isinstance(a, dict):
key, val = a.popitem()
return isinstance(b, dict) and key in b and compare_dicts(val, b.pop(key)) and compare_dicts(a, b)
return a == b
这将消耗 a 和 b 字典。如果有人知道避免这种情况的好方法,而无需像其他答案那样采用部分迭代解决方案,请告诉我。我需要一种方法来根据键将字典分成头部和尾部。
此代码作为编程练习更有用,并且可能比此处混合递归和迭代的其他解决方案慢很多。 @Nutcracker's solution 非常适合嵌套字典。
【讨论】:
代码中缺少某些内容。它只是从a
开始的第一个值下降(以及任何后续的第一个值)popitem
找到。它还应该检查同一级别的其他项目。我有成对的嵌套字典,它返回错误的答案。 (这里很难展示一个面向未来的示例,因为它依赖于popitem
的顺序)
谢谢,现在应该修好了:)【参考方案14】:
这是一个解决方案,它也可以正确地递归到字典中包含的列表和集合中。您也可以将其用于包含字典等的列表...
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)
# assume that subset is a plain value if none of the above match
return subset == superset
【讨论】:
谢谢。适用于嵌套字典。 这对于 "name" : "Girls" 的子集和 "show": "name": "Girls" 的超集失败了 那是因为它不是一个子集。如果我们认为 dicts 是(键值)元组的可搜索集。两个集合都有一个元素:一个具有键值元组“name”:“Girls”,另一个具有由键值元组“show”组成的单个元素:“name”:“Girls”,当两个集合都有一个元素,这些元素必须相等才能使集合被视为彼此的子集。显然不是这样,它们都是键值元组,但是一个有键名,另一个有键显示,一个有值 Girls,另一个有另一个键值元组形式的值. 即使我对递归子集的定义放宽了“对于子集中的每个元素都应该在超集中有一个元素等于该元素”的要求,对于“对于子集中的每个元素,都应该在超集中有一个元素该元素是其子集”,您的集合不是子集,因为元素出现的级别很重要。将家谱想象成字典:grandpa: child1:, child2: 不应该是 grandpa: dad: child1:, child2: 的子集 仅供参考,从技术上讲,如果两件事是等价的,那么根据集合论,它们都是彼此的子集。但在我个人的外行话中(也许还有许多其他人的话),同等事物不是彼此的子集。这对我来说没有意义;他们是等价的。所以,如果你和我一样,你可能想检查它们是否也等价。【参考方案15】:使用这个提供部分比较和漂亮差异的包装器对象:
class DictMatch(dict):
""" Partial match of a dictionary to another one """
def __eq__(self, other: dict):
assert isinstance(other, dict)
return all(other[name] == value for name, value in self.items())
actual_name = 'praenomen': 'Gaius', 'nomen': 'Julius', 'cognomen': 'Caesar'
expected_name = DictMatch('praenomen': 'Gaius') # partial match
assert expected_name == actual_name # True
【讨论】:
【参考方案16】:如果在 dict 中有一些其他 dicts 的数组,大多数答案将不起作用,这是一个解决方案:
def d_eq(d, d1):
if not isinstance(d, (dict, list)):
return d == d1
if isinstance(d, list):
return all(d_eq(a, b) for a, b in zip(d, d1))
return all(d.get(i) == d1[i] or d_eq(d.get(i), d1[i]) for i in d1)
def is_sub(d, d1):
if isinstance(d, list):
return any(is_sub(i, d1) for i in d)
return d_eq(d, d1) or (isinstance(d, dict) and any(is_sub(b, d1) for b in d.values()))
print(is_sub(dct_1, dict_2))
取自How to check if dict is subset of another complex dict
【讨论】:
【参考方案17】:另一种方法:
>>> d1 = 'a':'2', 'b':'3'
>>> d2 = 'a':'2', 'b':'3','c':'4'
>>> d3 = 'a':'1'
>>> set(d1.items()).issubset(d2.items())
True
>>> set(d3.items()).issubset(d2.items())
False
【讨论】:
【参考方案18】:对于 Python 3.9,这是我使用的:
def dict_contains_dict(small: dict, big: dict):
return (big | small) == big
【讨论】:
如何确定一个列表是不是是另一个列表的子集?
】如何确定一个列表是不是是另一个列表的子集?【英文标题】:Howtodetermineifalistissubsetofanotherlist?如何确定一个列表是否是另一个列表的子集?【发布时间】:2009-08-2615:53:06【问题描述】:确定一个列表是否是另一个列表的子... 查看详情
如何一次检查多个键是不是在一个字典中?
】如何一次检查多个键是不是在一个字典中?【英文标题】:HowdoIcheckthatmultiplekeysareinadictinasinglepass?如何一次检查多个键是否在一个字典中?【发布时间】:2010-11-2003:09:14【问题描述】:我想做这样的事情:foo=\'foo\':1,\'zip\':2,\'z... 查看详情
如何证明一个集合是另一个集合的子集
怎样证明一个集合是另一个集合的子集?怎样证明一个集合是另一个集合的子集,又怎样证明一个集合不是另一个集合的子集?参考技术A在一个集合中任取一个元素,都满足这个元素属于另一个集合,则这个集合是另一个集合的子集.... 查看详情
java示例代码_HQL(Hibernate)如何检查一个元素列表是否是另一个列表的子集
java示例代码_HQL(Hibernate)如何检查一个元素列表是否是另一个列表的子集 查看详情
如何检查变量是不是是Python中的字典?
】如何检查变量是不是是Python中的字典?【英文标题】:HowtocheckifavariableisadictionaryinPython?如何检查变量是否是Python中的字典?【发布时间】:2014-10-0314:45:52【问题描述】:如何检查一个变量是否是Python中的字典?例如,我希望... 查看详情
如何检查返回对象是不是是python中的字典[重复]
】如何检查返回对象是不是是python中的字典[重复]【英文标题】:Howtocheckifareturnobjectisadictionaryinpython[duplicate]如何检查返回对象是否是python中的字典[重复]【发布时间】:2021-12-2607:48:05【问题描述】:我编写了一个函数f(x),它要... 查看详情
如何提取swift 3字典的子集
】如何提取swift3字典的子集【英文标题】:Howtoextractasubsetofaswift3Dictionary【发布时间】:2017-01-0418:45:49【问题描述】:我查看了methodshere,但找不到我要找的东西。我是Swift的新手。我想根据一组键值从字典中提取一个子集,最好... 查看详情
如何使用 itertools 模块在排序列表中获取下一个字典顺序更大的字符串?
】如何使用itertools模块在排序列表中获取下一个字典顺序更大的字符串?【英文标题】:Howtogetthenextlexicographicallybiggerstringinasortedlistbyusingitertoolsmodule?【发布时间】:2017-03-2305:09:02【问题描述】:我需要输入一个字符串,并返回... 查看详情
如何检查字典python中是不是存在多个值
】如何检查字典python中是不是存在多个值【英文标题】:Howtocheckifmultiplevaluesexistsinadictionarypython如何检查字典python中是否存在多个值【发布时间】:2021-12-1902:09:38【问题描述】:我有一本看起来像这样的字典:word_freq="Hello":56,"at... 查看详情
检查字典是不是包含 Swift 中的值
】检查字典是不是包含Swift中的值【英文标题】:CheckifdictionarycontainsvalueinSwift检查字典是否包含Swift中的值【发布时间】:2016-07-1906:43:38【问题描述】:只是简单的任务。我有一本字典vartypes=[Int:String](),它像一个空的一样初始... 查看详情
如何检查一个目录是不是是另一个目录的子目录
】如何检查一个目录是不是是另一个目录的子目录【英文标题】:Howtocheckwhetheradirectoryisasubdirectoryofanotherdirectory如何检查一个目录是否是另一个目录的子目录【发布时间】:2011-04-1806:58:58【问题描述】:我喜欢用Python编写一个模... 查看详情
如何检查字典值是不是在 python 的字典列表中可用?
】如何检查字典值是不是在python的字典列表中可用?【英文标题】:Howcanicheckdictionaryvalueisavailableinlistofdictionaryinpython?如何检查字典值是否在python的字典列表中可用?【发布时间】:2018-12-0812:59:39【问题描述】:我想检查a的值是... 查看详情
Python:如何检查键是不是存在并按降序从字典中检索值
】Python:如何检查键是不是存在并按降序从字典中检索值【英文标题】:Python:HowtocheckifkeysexistsandretrievevaluefromDictionaryindescendingpriorityPython:如何检查键是否存在并按降序从字典中检索值【发布时间】:2013-06-2222:05:52【问题描述... 查看详情
检查一个键是不是存在并且它的值不是 Python 字典中的空字符串
】检查一个键是不是存在并且它的值不是Python字典中的空字符串【英文标题】:CheckingifakeyexistsanditsvalueisnotanemptystringinaPythondictionary检查一个键是否存在并且它的值不是Python字典中的空字符串【发布时间】:2012-12-2816:25:37【问题... 查看详情
如何检查 NSDictionary 中的值是不是存在于字典数组中
】如何检查NSDictionary中的值是不是存在于字典数组中【英文标题】:HowtocheckifthevalueinanNSDictionaryexistsinanarrayofdictionarys如何检查NSDictionary中的值是否存在于字典数组中【发布时间】:2010-09-1414:55:26【问题描述】:标题有点混乱…... 查看详情
如果数据框列值匹配字典键,检查不同的列是不是匹配字典值
】如果数据框列值匹配字典键,检查不同的列是不是匹配字典值【英文标题】:Ifdataframecolumnvaluematchesdictionarykey,checkifdifferentcolumnmatchesdictionaryvalue如果数据框列值匹配字典键,检查不同的列是否匹配字典值【发布时间】:2020-09-1... 查看详情
Python检查字典中是不是存在值[重复]
】Python检查字典中是不是存在值[重复]【英文标题】:Pythoncheckifvalueexistsindictionary[duplicate]Python检查字典中是否存在值[重复]【发布时间】:2015-12-0604:00:39【问题描述】:我有一个Python字典,如下:users=\'user\':\'pw\':\'password\'如何... 查看详情
如何检查一个数组是不是是 JavaScript 中另一个数组的子集?
】如何检查一个数组是不是是JavaScript中另一个数组的子集?【英文标题】:HowtocheckifanarrayisasubsetofanotherarrayinJavaScript?如何检查一个数组是否是JavaScript中另一个数组的子集?【发布时间】:2016-12-1304:17:35【问题描述】:假设我有... 查看详情