首页 > 解决方案 > 如何获取/打印两个字典之间的差异?

问题描述

我有两个必须返回相同字典的函数(一个是旧方法,另一个是替换旧方法的新方法)。当我测试新函数给我的结果与旧函数相同时。我正在尝试创建一个程序,该程序将两个字典作为输入,并验证它们是否具有相同的信息并告诉我它们之间的任何差异。我的范围是了解新功能的哪些信息是错误的。

这两个字典每次都可以更改。它们可能具有仅包含字符串或字典或字典列表的键。此外,这些字典列表可能包含具有字符串值的键或字典或另一个字典列表。字典可以任意复杂。

我试过这个,但结果并不好。 attr_prod是返回旧函数的字典示例。 attr_test是返回新函数的字典示例。

def main():
    attr_prod = {
            'key1': 'a',
            'key2': [ {
                        'key3': 'n1',
                        'key4': 'n2',
                        'key5': [ {
                                    'key6': 'n1',
                                    'key7': 'n2',
                                    'key8': {
                                        'key10': 'g1',
                                        'key11': 'g2',
                                        'key12': 'g3'
                                        }
                                    },
                                    {
                                    'key6': 'n5',
                                    'key7': 'n6',
                                    'key8': {
                                        'key10': 'g4',
                                        'key11': 'g5',
                                        'key12': 'g6'
                                    }
                                 }
                                ]
                        }
                    ],
            'key20': {
                        'key21': 'g4',
                        'key22': 'g5',
                        'key23': 'g6'
                    }
        }

    attr_test = {
            'key1': 'a',
            'key2': [ {
                        'key3': 'different info',
                        'key4': 'n2',
                        'key5': [   {
                                    'key6': 'n1',
                                    'key7': 'n2',
                                    'key8': {
                                        'key10': 'g1',
                                        'key11': 'g2',
                                        'key12': 'g3'
                                        }
                                    },
                                    {
                                    'key6': 'n5',
                                    'key7': 'n6',
                                    'key8': {
                                        'key10': 'different info',
                                        'key11': 'g5',
                                        'key12': 'g6'
                                        }
                                    },
                                    {
                                    'key6': 'this is new',
                                    'key7': 'this is new',
                                    'key8': {
                                        'key10': 'new',
                                        'key11': 'new',
                                        'key12': 'new'
                                    }
                                }
                            ]
                        }
                    ],
            'key20': {
                        'key21': 'g4',
                        'key22': 'different info',
                        'key23': 'g6'
                    }
        }

    for key, value_prod in attr_prod.items():
            if isinstance(value_prod, basestring):
                check(key, value_prod, attr_test[key])
            elif isinstance(value_prod, list):
                n_rec = 0
                for rec in value_prod:
#                   if isinstance(rec, basestring):
#                       check(key, rec, attr_test[key][n_rec])
                    print rec
                    if isinstance(rec, dict):
                        for key2, value_prod2 in rec.items():
                            if isinstance(value_prod2, basestring):
                                check(key, value_prod2, attr_test[key][n_rec][key2])
                            elif isinstance(value_prod2, list):
                                n_rec2 = 0
                                for rec2 in value_prod2:
                                    for key3, value_prod3 in rec2.items():
                                        if isinstance(value_prod3, basestring):
                                            check(key, value_prod3, attr_test[key][n_rec][key2][n_rec2][key3])
                                n_rec2 += 1
                    n_rec += 1


def check(key, value_prod, value_test):
    if value_test != value_prod:
        print "KO key: %s test: -%s- prod: -%s-" % (key, value_test, value_prod)
    

标签: pythondictionaryrecursioncompare

解决方案


我建议将递归字典比较函数用作生成器(从而允许您使用下一个函数有效地检测至少一个差异):

def compareDict(before,after):
    for k,old in before.items():
        if k not in after: yield f"{k}: deleted";continue
        new = after[k]
        if type(old) != type(new):
            yield f"{k}: changed from: {old}"
            yield f"{k}: changed   to: {new}"
        elif isinstance(old,dict):
            yield from (f"{k}:{change}" for change in compareDict(old,new))
        elif isinstance(old,(tuple,list)):
            b = {f"[{i}]":v for i,v in enumerate(old)}
            a = {f"[{i}]":v for i,v in enumerate(new)}
            yield from (f"{k}:{change}" for change in compareDict(b,a))
        elif old != new:
            yield f"{k}: changed from: {old}"
            yield f"{k}: changed   to: {new}"
    for k,new in after.items():
        if k not in before: yield f"{k}: added: {new}"

输出:

for change in compareDict(attr_prod,attr_test): print(change)

key2:[0]:key3: changed from: n1
key2:[0]:key3: changed   to: different info
key2:[0]:key5:[1]:key8:key10: changed from: g4
key2:[0]:key5:[1]:key8:key10: changed   to: different info
key2:[0]:key5:[2]: added: {'key6': 'this is new', 'key7': 'this is new', 'key8': {'key10': 'new', 'key11': 'new', 'key12': 'new'}}
key20:key22: changed from: g5
key20:key22: changed   to: different info

推荐阅读