python 比较两个嵌套字典键

mzillmmw  于 2023-01-04  发布在  Python
关注(0)|答案(3)|浏览(154)

我只需要比较两个嵌套字典的键,主要用于外部API响应的实时测试,以防止响应更改。
例如,这两个字典匹配,但它们的值不同:

EDIT:这是一个示例,实际的字典有动态键,可能更大,由整数、字符串和布尔值组成

dict1 = {"guid": {"id": {"addr": "foo", "creation_num": "4"}}}
dict2 = {"guid": {"id": {"addr": "bar", "creation_num": "2"}}}

我尝试通过以下方法重置字典的值来做到这一点:

def reset_values(dictionary, reset_value=0):
    for key, value in dictionary.items():
        if type(value) is dict:
            dictionary[key] = reset_values(dictionary[key], reset_value)
        else:
            dictionary[key] = reset_value
    return dictionary

这个方法是可行的,但是有没有更像Python的、更直接的方法?

nbnkbykc

nbnkbykc1#

    • 编辑**

@Bheid说得对,如果将键列表扁平化,当两个字典具有相同的键但嵌套层次不同时,我的解决方案就会出错。

if isinstance(v, dict):
    klist.extend(get_keys(v))

致:

if isinstance(v, dict):
    klist.append(get_keys(v))

想法相同,但编辑后的版本保留了嵌套的关键级别。
如果我理解你要解决的问题,那就是两个字典的比较键(以及嵌套字典的子键)而不管关联的值。如果两个字典具有相同的键(和子键),那么它们对于您的目的是"相同的"。如果问题陈述是正确的,那么生成键/子键的有序列表。一个字典的关键字并将该列表与第二个字典的相同列表进行比较就足以满足您的目的:

dict1 = {"guid": {"id": {"addr": "foo", "creation_num": "4"}}}
dict2 = {"guid": {"id": {"addr": "bar", "creation_num": "2"}}}

def get_keys(d):
    klist = []
    for k, v in d.items():
        klist.append(k)
        if isinstance(v, dict):
            klist.extend(get_keys(v))
            
    return klist

print(get_keys(dict1) == get_keys(dict2))

输出:

True
5gfr0r5j

5gfr0r5j2#

答案

您可以使用ndicts包来完成此操作。

pip install ndicts

然后简单地将您的字典转换为NestedDict

from ndicts import NestedDict

dict1 = {"guid": {"id": {"addr": "foo", "creation_num": "4"}}}
dict2 = {"guid": {"id": {"addr": "bar", "creation_num": "2"}}}
nd1 = NestedDict(dict1)
nd2 = NestedDict(dict2)

然后可以检查密钥是否相等:

>>> nd1.keys() == nd2.keys()
True

下面是NestedDict的键:

>>> for k in nd1.keys():
...     print(k)
('guid', 'id', 'addr')
('guid', 'id', 'creation_num')

对您的解决方案进行注解

您的方法可以工作,但作为一个潜在的不希望的副作用,它将修改输入字典:

>>> dict1
{"guid": {"id": {"addr": "foo", "creation_num": "4"}}}
>>> reset_values(dict1)
{'guid': {'id': {'addr': 0, 'creation_num': 0}}}
>>> dict1
{'guid': {'id': {'addr': 0, 'creation_num': 0}}}

这可以通过在函数开始时深拷贝输入字典来很容易地修复。
你使用的是递归,这很好。但是,你也可以使用for循环或者reduce,它们有一些优点。参见answer to "Best way to get nested dictionary items"
最后一件事,我的目标是创建一个函数,它直接比较键或者返回一个可迭代对象中的所有键,而不是重新设置字典的值,然后再比较它们。

cnh2zyt3

cnh2zyt33#

你可以通过创建一个字典散列来解决这个问题,这个解决方案也考虑了不同的键顺序。

import hashlib

def has_exact_keys(d: dict, z: dict) -> bool:
    return dict_keys_hash(d) == dict_keys_hash(z)

def dict_keys_hash(d: dict) -> str:
    hash = hashlib.md5() # switch to different hashing algorithm if you want 
    for k in sorted(d.keys()):
        if isinstance(d[k], dict):
            hash.update(dict_hash(d[k]).encode('utf-8'))
        hash.update(k.encode('utf-8'))
    return hash.hexdigest()

相关问题