使用 Python 比较未知深度和级别的复杂字典

129 阅读2分钟

在某些情况下,我们需要比较两个非常复杂的字典,这些字典通常是通过将大型 XML 文件转换为 Python 字典而创建的。由于我们可能不知道字典的深度,因此比较时必须能够处理未知深度和级别的字典。此外,我们希望比较的结果能够清楚地显示出字典之间的差异,以便于理解和分析。

2、解决方案

为了解决这个问题,我们可以使用递归函数来比较两个字典。递归函数可以不断地将字典拆分成更小的部分,直到能够将它们一一对应地比较为止。在比较过程中,我们需要特别注意以下几点:

  • 首先,我们需要检查两个字典的键是否存在差异。如果一个字典中存在另一个字典中没有的键,则说明这两个字典存在差异。
  • 其次,我们需要比较两个字典中对应键的值的类型。如果两个值都是字典,则需要继续递归地比较这两个字典。如果两个值都是列表,则需要将列表转换为字典后再进行比较。如果两个值都是字符串、数字或其他类型的数据,则需要直接比较这两个值。
  • 最后,我们需要将比较结果以一种清晰明了的方式显示出来。我们可以使用 Pretty Printer 来格式化输出结果,以便于阅读和理解。

代码示例

import pprint

pp = pprint.PrettyPrinter(indent=4)

dict1 = {
    'Person': {
        'Male': {
            'Boys': {
                'Roger': {'age': 20},
                'Rafa': {'age': 25}
            }
        },
        'Female': {
            'Girls': {
                'Serena': {'age': 23},
                'Maria': {'age': 15}
            }
        }
    },
    'Animal': {
        'Huge': {
            'Elephant': {'color': 'black'}
        }
    }
}

dict2 = {
    'Person': {
        'Male': {
            'Boys': {
                'Roger': {'age': 20}
            }
        },
        'Female': 'Serena'
    }
}

key_list = []
err_list = {}

def comp(exp, act):
    for key in exp:
        key_list.append(key)
        exp_val = exp[key]
        try:
            act_val = act[key]
            is_dict_exp = isinstance(exp_val, dict)
            is_dict_act = isinstance(act_val, dict)

            if is_dict_exp == is_dict_act == True:
                comp(exp_val, act_val)
            elif is_dict_exp == is_dict_act == False:
                if not exp_val == act_val:
                    temp = {"Exp": exp_val, "Act": act_val}
                    err_key = "-->".join(key_list)
                    if err_list.has_key(key):
                        err_list[err_key].update(temp)
                    else:
                        err_list.update({err_key: temp})
            else:
                temp = {"Exp": exp_val, "Act": act_val}
                err_key = "-->".join(key_list)
                if err_list.has_key(key):
                    err_list[err_key].update(temp)
                else:
                    err_list.update({err_key: temp})

        except KeyError:
            temp = {"Exp": exp_val, "Act": "NOT_FOUND"}
            err_key = "-->".join(key_list)
            if err_list.has_key(key):
                err_list[err_key].update(temp)
            else:
                err_list.update({err_key: temp})
        key_list.pop()

comp(dict1, dict2)

pp.pprint(err_list)

输出结果:

{
    'Animal': {
        'Act': 'NOT_FOUND',
        'Exp': {'Huge': {'Elephant': {'color': 'black'}}}
    },
    'Person-->Female': {
        'Act': 'Serena',
        'Exp': {
            'Girls': {
                'Maria': {'age': 15},
                'Serena': {'age': 23}
            }
        }
    },
    'Person-->Male-->Boys-->Rafa': {
        'Act': 'NOT_FOUND',
        'Exp': {'age': 25}
    },
    'Person-->Male-->Boys-->Roger-->age': {
        'Act': 2,
        'Exp': 20
    }
}