在某些情况下,我们需要比较两个非常复杂的字典,这些字典通常是通过将大型 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
}
}