Python 按值比较2个字典

Python 按值比较2个字典,python,python-3.x,Python,Python 3.x,我需要比较两个超过600k键的大型词典 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',

我需要比较两个超过600k键的大型词典

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风格的方法来执行此操作?

您不需要在键上执行嵌套循环。相反,您可以只检查dict\u old中的key\u new是否存在,如果存在,则比较这些值并进行更新

for key_new in dict_new.keys():
    if (dict_old.get(key_new) and dict_old[key_new] == dict_new[key_new]):
        dict_update[key_new] = dict_old[key_new]

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

代码的问题在于,对于dict2中的每个键值对,您都在对dict1进行线性搜索。所以,这需要*M时间,其中N=lendict2和M=lendict1,这非常慢

但是如果你可以把dict1中的值放在一个集合中,你就不需要线性搜索;你们可以在测试中做一个固定的时间。你可以一开始就制作一次。所以现在它只在+M上,这更好

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

有几种方法可以解决这个问题,但最简单的方法是将dict转换为可散列的内容,以保持平等性。例如,假设内部值可哈希且键可排序,则已排序键值对的元组是可哈希的,这两个值在这里都是真的,并且在原始dict相等时都是相等的

因此:

请注意,这并没有为您提供所需的输出,它只提供以下内容:

{2: {'value_1': '222', 'value_2': '333'}}
但是您现有的代码提供了完全相同的东西,而且它似乎正是您所要求的东西。

这个怎么样:

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_old中,它就会被添加到dict_更新中


您应该能够调整此代码,以防它不能完全满足您的需要,例如,也可以按相反的方向执行,并将其添加到dict_更新中。

此处的更改算什么?看起来您的第一个更改是一个在dict_old和dict_new dict_old[2]==dict_new[1]中都相同的值,您的第二个更改是一个仅在dict_new dict_new[2]中的值,而您跳过了两个dict_old[1]==dict_new[3]中的其他值,所以我不知道你要实现什么规则。它可能很简单,比如old_values=setdict_old.values,然后dict_update={key:value for key,value not in dict_new.items if value in old_values}或其他什么,这将使二次嵌套循环变成线性平坦循环,因为您可以在恒定时间内设置查找。但是这显然不适合你想要的输出,如果不理解为什么想要的输出是这样的,我不知道是否有可能做类似的事情是正确的。dict_old[1]==dict_new[3]是可能的,键并不重要-我只需要比较值,但这根本不能回答我的问题。为什么dict_更新的第一行是?为什么dict_更新中的第二行是?为什么dict_update中没有与第3行对应的内容?当第1行和第4行相同时,为什么只有一行对应于它们?我甚至不能通过运行你的代码来解决这个问题,因为,即使我删除了所有。。。要将示例转换为可运行的示例,您的代码不会生成与示例输出相同的输出。。。没关系,那么为什么{'value_1':'abc','value_2':'def',…}在dict_update中?如果只有值是重要的,那么@abarnert的set解决方案是好的。键是滚动数字,在旧/新字典中不一样。您的答案假设键对齐,因此它不会满足OP的要求。我真的不知道OP想要什么,除了这个,但是…应该是dict_old.getkey_new和。。。。如果dict中没有这样的键,dict_old[key_new]将引发一个keyrerror。不,它不假设键对齐。它假设OP只关心已经在new_dict中的键。如果key_new不在dict_old中,if语句将不会执行第二次检查。虽然我同意,但我并不确定OP的目标是什么。这更能说明循环只需要1。您要求的是dict_old[key_new]==dict_new[key_new]。这假设钥匙排成一行。他想处理dict_old[some_key]==dict_new[some_other_key]的情况。啊,我明白了,我当时误解了按键排列的意思。谢谢你的澄清。最好删除这个答案?它只返回所有4个值,因为现在没有匹配项。这可能是OP想要的,但我不这么认为;我们只能猜测OP到底想要什么。
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}