按值比较2个字典

时间:2018-08-28 19:52:50

标签: python python-3.x

我需要比较2个大型词典(超过60万个键)。

dict_old = {
    1: {'value_1' : 'foo', 'value_2' : 'bar', ...},
    2: {'value_1' : 'abc', 'value_2' : 'def', ...},
    3: {....},
    }

dict_new = {
    1: {'value_1' : 'abc', 'value_2' : 'def', ...},
    2: {'value_1' : '222', 'value_2' : '333', ...},
    3: {'value_1' : 'foo', 'value_2' : 'bar', ...},
    4: {'value_1' : 'abc', 'value_2' : 'def', ...},
    ...
    }   

我必须创建一个仅包含更改的新词典。

dict_update = {
    1: {'value_1' : 'abc', 'value_2' : 'def', ...},
    2: {'value_1' : '222', 'value_2' : '333', ...},
    ...
    }

键是滚动数字,在新旧字典中不同。因此,我使用2 for循环来完成这项工作。 该过程需要60分钟才能运行。

dict_update = {}

for key_new in dict_new.keys():
    for key_old in dict_old.keys():
        if dict_new[key_new] == dict_old[key_old]:
            add = False
            break
        else:
            add = True

    if add:
        dict_update[key_new] = dict_new[key_new]

是否有更快/更Python化的方式来做到这一点?

2 个答案:

答案 0 :(得分:1)

我将在这里进行一个疯狂的猜测:您想要的是dict_new中的所有键值对,而dict_old中没有相等的值。

代码的问题在于,对于dict2中的每个键值对,您都在整个dict1中进行线性搜索。因此,这花费了O(N*M)时间(其中N=len(dict2)M=len(dict1)),这很慢。

但是,如果您可以将dict1中的值放在一组中,则不需要线性搜索;您可以进行恒定时间in测试。您一开始就可以构建该集合。所以现在只有O(N+M),更好。


唯一的问题是您的值是字典,您不能将字典存储在集合中,因为它们是可变的。

有几种方法可以解决此问题,但最简单的方法是将dict转换为可哈希的对象,并保持相等性。例如,排序后的键/值对的元组是可哈希的(假设内部值是可哈希的,并且键是可排序的,这两个都是正确的),并且只要原始字典相等就将相等。

所以:

dict_old = {
    1: {'value_1' : 'foo', 'value_2' : 'bar'},
    2: {'value_1' : 'abc', 'value_2' : 'def'},
    }

dict_new = {
    1: {'value_1' : 'abc', 'value_2' : 'def'},
    2: {'value_1' : '222', 'value_2' : '333'},
    3: {'value_1' : 'foo', 'value_2' : 'bar'},
    4: {'value_1' : 'abc', 'value_2' : 'def'},
    }   

def transform(d):
    return tuple(sorted(d.items()))

set_old = set(transform(d) for d in dict_old.values())

dict_update = {key: value for key, value in dict_new.items()
               if transform(value) not in set_old}

请注意,这并不能为您提供所需的输出,而只是为您提供:

{2: {'value_1': '222', 'value_2': '333'}}

但是您现有的代码可以给您完全一样的东西,而且这似乎是您要的东西。

答案 1 :(得分:0)

如何?

dict_old = {
    1: {'value_1' : 'foo', 'value_2' : 'bar'},
    2: {'value_1' : 'abc', 'value_2' : 'def'}
    }

dict_new = {
    1: {'value_1' : 'abc', 'value_2' : 'def'},
    2: {'value_1' : '222', 'value_2' : '333'},
    3: {'value_1' : 'foo', 'value_2' : 'bar'},
    4: {'value_1' : 'abc', 'value_2' : 'def'},
    }


old_hashes = set((k, frozenset(v.items())) for k, v in dict_old.items())

dictionary_update = {k: v for k, v in dict_new.items()
                     if (k, frozenset(v.items())) not in old_hashes}

这里的理由(如果您要的是)是每当滚动数字+键及其值不在dict_old中时,它就会被添加到dict_update中。 / p>

如果该代码不能完全满足您的需要(例如,也可以按照相反的方向进行操作,然后将其添加到dict_update中),您应该可以对其进行调整。