比较Python中的两个词典

时间:2010-12-24 19:09:13

标签: python dictionary comparison

我有两个词典,但为了简化,我将采用这两个词典:

>>> x = dict(a=1, b=2)
>>> y = dict(a=2, b=2)

现在,我想比较key, value中的每个x对是否在y中具有相同的对应值。所以我写了这个:

>>> for x_values, y_values in zip(x.iteritems(), y.iteritems()):
        if x_values == y_values:
            print 'Ok', x_values, y_values
        else:
            print 'Not', x_values, y_values

它起作用,因为返回tuple然后比较相等。

我的问题:

这是对的吗?有没有更好的方法来做到这一点?更好的不是速度,我说的是代码优雅。

更新:我忘了提到我必须检查有多少key, value对相等。

26 个答案:

答案 0 :(得分:155)

您想要做的只是x==y

你所做的并不是一个好主意,因为词典中的项目不应该有任何顺序。您可能会将[('a',1),('b',1)][('b',1), ('a',1)](相同的词典,不同的顺序)进行比较。

例如,请看:

>>> x = dict(a=2, b=2,c=3, d=4)
>>> x
{'a': 2, 'c': 3, 'b': 2, 'd': 4}
>>> y = dict(b=2,c=3, d=4)
>>> y
{'c': 3, 'b': 2, 'd': 4}
>>> zip(x.iteritems(), y.iteritems())
[(('a', 2), ('c', 3)), (('c', 3), ('b', 2)), (('b', 2), ('d', 4))]

差异只是一个项目,但您的算法会看到所有项目不同

答案 1 :(得分:143)

如果你想知道两个字典中有多少个值匹配,你应该说:)

也许是这样的:

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print len(shared_items)

答案 2 :(得分:135)

def dict_compare(d1, d2):
    d1_keys = set(d1.keys())
    d2_keys = set(d2.keys())
    intersect_keys = d1_keys.intersection(d2_keys)
    added = d1_keys - d2_keys
    removed = d2_keys - d1_keys
    modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]}
    same = set(o for o in intersect_keys if d1[o] == d2[o])
    return added, removed, modified, same

x = dict(a=1, b=2)
y = dict(a=2, b=2)
added, removed, modified, same = dict_compare(x, y)

答案 3 :(得分:74)

dic1 == dic2

来自python docs

  

为了说明,以下示例都返回字典相等   {"one": 1, "two": 2, "three": 3}

>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True
     

提供第一个示例中的关键字参数仅适用于   密钥是有效的Python标识符。否则,任何有效的密钥都可以   使用。

适用于py2py3

答案 4 :(得分:51)

我是python的新手,但我最终做了类似@mouad

的事情
unmatched_item = set(dict_1.items()) ^ set(dict_2.items())
len(unmatched_item) # should be 0

XOR运算符(^)应该在两个词组中相同时删除dict的所有元素。

答案 5 :(得分:43)

只需使用:

assert cmp(dict1, dict2) == 0

答案 6 :(得分:23)

由于似乎没有人提到deepdiff,我会在这里添加它只是为了完整性。 我发现通常可以非常方便地获取(嵌套)对象的差异。

import deepdiff
from pprint import pprint

aa = {
    "a": 1,
    "nested": {
        "b": 1,
    }
}
bb = {
    "a": 2,
    "nested": {
        "b": 2,
    }
}
pprint(deepdiff.DeepDiff(aa, bb))

输出:

{'values_changed': {"root['a']": {'new_value': 2, 'old_value': 1},
                "root['nested']['b']": {'new_value': 2, 'old_value': 1}}}

注:

    需要安装
  • deepdiff包,因为这不是标准包

  • 必须付出一些努力才能解析结果

然而,为了获取词典的差异,我发现dictdiffer非常方便。

答案 7 :(得分:8)

如果你假设两个词典只包含简单的值,那么@mouad的回答很好。但是,如果你有包含词典的词典,你会得到一个例外,因为词典不可用。

脱离我的头脑,这样的事情可能有用:

def compare_dictionaries(dict1, dict2):
     if dict1 is None or dict2 is None:
        print('Nones')
        return False

     if (not isinstance(dict1, dict)) or (not isinstance(dict2, dict)):
        print('Not dict')
        return False

     shared_keys = set(dict2.keys()) & set(dict2.keys())

     if not ( len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())):
        print('Not all keys are shared')
        return False


     dicts_are_equal = True
     for key in dict1.keys():
         if isinstance(dict1[key], dict) or isinstance(dict2[key], dict):
             dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key], dict2[key])
         else:
             dicts_are_equal = dicts_are_equal and all(atleast_1d(dict1[key] == dict2[key]))

     return dicts_are_equal

答案 8 :(得分:6)

另一种可能性,直到OP的最后一个注释,是比较作为JSON转储的词干的哈希值(SHAMD)。构造哈希的方式保证如果它们相等,源字符串也是相等的。这是非常快速和数学上的声音。

import json
import hashlib

def hash_dict(d):
    return hashlib.sha1(json.dumps(d, sort_keys=True)).hexdigest()

x = dict(a=1, b=2)
y = dict(a=2, b=2)
z = dict(a=1, b=2)

print(hash_dict(x) == hash_dict(y))
print(hash_dict(x) == hash_dict(z))

答案 9 :(得分:4)

测试两个dicts在键和值中是否相等:

def dicts_equal(d1,d2):
    """ return True if all keys and values are the same """
    return all(k in d2 and d1[k] == d2[k]
               for k in d1) \
        and all(k in d1 and d1[k] == d2[k]
               for k in d2)

如果要返回不同的值,请以不同方式写入:

def dict1_minus_d2(d1, d2):
    """ return the subset of d1 where the keys don't exist in d2 or
        the values in d2 are different, as a dict """
    return {k,v for k,v in d1.items() if k in d2 and v == d2[k]}

你必须叫它两次,即

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))

答案 10 :(得分:3)

代码

def equal(a, b):
    type_a = type(a)
    type_b = type(b)

    if type_a != type_b:
        return False

    if isinstance(a, dict):
        if len(a) != len(b):
            return False
        for key in a:
            if key not in b:
                return False
            if not equal(a[key], b[key]):
                return False
        return True

    elif isinstance(a, list):
        if len(a) != len(b):
            return False
        while len(a):
            x = a.pop()
            index = indexof(x, b)
            if index == -1:
                return False
            del b[index]
        return True

    else:
        return a == b

def indexof(x, a):
    for i in range(len(a)):
        if equal(x, a[i]):
            return i
    return -1

测试

>>> a = {
    'number': 1,
    'list': ['one', 'two']
}
>>> b = {
    'list': ['two', 'one'],
    'number': 1
}
>>> equal(a, b)
True

答案 11 :(得分:3)

该功能很好IMO,清晰直观。但只是给你(另一个)答案,这是我的去处:

def compare_dict(dict1, dict2):
    for x1 in dict1.keys():
        z = dict1.get(x1) == dict2.get(x1)
        if not z:
            print('key', x1)
            print('value A', dict1.get(x1), '\nvalue B', dict2.get(x1))
            print('-----\n')

对您或其他任何人都有用..

答案 12 :(得分:2)

对于python3:

data_set_a = dict_a.items()
data_set_b = dict_b.items()

difference_set = data_set_a ^ data_set_b

答案 13 :(得分:2)

我正在使用此解决方案,该解决方案在Python 3中非常适合我


import logging
log = logging.getLogger(__name__)

...

    def deep_compare(self,left, right, level=0):
        if type(left) != type(right):
            log.info("Exit 1 - Different types")
            return False

        elif type(left) is dict:
            # Dict comparison
            for key in left:
                if key not in right:
                    log.info("Exit 2 - missing {} in right".format(key))
                    return False
                else:
                    if not deep_compare(left[str(key)], right[str(key)], level +1 ):
                        log.info("Exit 3 - different children")
                        return False
            return True
        elif type(left) is list:
            # List comparison
            for key in left:
                if key not in right:
                    log.info("Exit 4 - missing {} in right".format(key))
                    return False
                else:
                    if not deep_compare(left[left.index(key)], right[right.index(key)], level +1 ):
                        log.info("Exit 5 - different children")
                        return False
            return True
        else:
            # Other comparison
            return left == right

        return False

它比较dict,list和其他自己实现“ ==”运算符的类型。 如果您需要比较其他不同的东西,则需要在“如果树”中添加一个新分支。

希望有帮助。

答案 14 :(得分:1)

为什么不仅仅遍历一个词典并检查另一个词典(假设两个词典具有相同的键)?

x = dict(a=1, b=2)
y = dict(a=2, b=2)

for key, val in x.items():
    if val == y[key]:
        print ('Ok', val, y[key])
    else:
        print ('Not', val, y[key])

输出:

Not 1 2
Ok 2 2

答案 15 :(得分:1)

查看字典视图对象: https://docs.python.org/2/library/stdtypes.html#dict

这样你可以从dictView1中减去dictView2,它将返回一组dictView2中不同的键/值对:

original = {'one':1,'two':2,'ACTION':'ADD'}
originalView=original.viewitems()
updatedDict = {'one':1,'two':2,'ACTION':'REPLACE'}
updatedDictView=updatedDict.viewitems()
delta=original | updatedDict
print delta
>>set([('ACTION', 'REPLACE')])

你可以交叉,结合,差异(如上所示),这些字典视图对象的对称差异 更好?快点? - 不确定,但标准库的一部分 - 这使其成为便携性的一大优势

答案 16 :(得分:1)

迟到总比没有好!

比较Not_Equal比比较Equal更有效。因此,如果在一个字典中没有找到任何键值,则两个字典不相等。下面的代码考虑到您可能会比较默认字典,因此使用get代替 getitem []。

在get调用中使用一种随机值作为默认值,该值等于要检索的键-以防万一,该字典在一个字典中具有None值,而在另一个字典中不存在该键。同样,在不使用条件之前检查get!=条件是为了提高效率,因为您正在同时检查双方的键和值。

def Dicts_Not_Equal(first,second):
    """ return True if both do not have same length or if any keys and values are not the same """
    if len(first) == len(second): 
        for k in first:
            if first.get(k) != second.get(k,k) or k not in second: return (True)
        for k in second:         
            if first.get(k,k) != second.get(k) or k not in first: return (True)
        return (False)   
    return (True)

答案 17 :(得分:1)

下面的代码将帮助您比较python中的字典列表

def compate_generic_types(object1, object2):
    if isinstance(object1, str) and isinstance(object2, str):
        return object1 == object2
    elif isinstance(object1, unicode) and isinstance(object2, unicode):
        return object1 == object2
    elif isinstance(object1, bool) and isinstance(object2, bool):
        return object1 == object2
    elif isinstance(object1, int) and isinstance(object2, int):
        return object1 == object2
    elif isinstance(object1, float) and isinstance(object2, float):
        return object1 == object2
    elif isinstance(object1, float) and isinstance(object2, int):
        return object1 == float(object2)
    elif isinstance(object1, int) and isinstance(object2, float):
        return float(object1) == object2

    return True

def deep_list_compare(object1, object2):
    retval = True
    count = len(object1)
    object1 = sorted(object1)
    object2 = sorted(object2)
    for x in range(count):
        if isinstance(object1[x], dict) and isinstance(object2[x], dict):
            retval = deep_dict_compare(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False
        elif isinstance(object1[x], list) and isinstance(object2[x], list):
            retval = deep_list_compare(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False
        else:
            retval = compate_generic_types(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False

    return retval

def deep_dict_compare(object1, object2):
    retval = True

    if len(object1) != len(object2):
        return False

    for k in object1.iterkeys():
        obj1 = object1[k]
        obj2 = object2[k]
        if isinstance(obj1, list) and isinstance(obj2, list):
            retval = deep_list_compare(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False

        elif isinstance(obj1, dict) and isinstance(obj2, dict):
            retval = deep_dict_compare(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False
        else:
            retval = compate_generic_types(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False

    return retval

答案 18 :(得分:1)

在Python 3.6中,它可以完成: -

if (len(dict_1)==len(dict_2): 
  for i in dict_1.items():
        ret=bool(i in dict_2.items())
如果dict_2中存在dict_1的所有项目

,则

ret变量将为true

答案 19 :(得分:1)

In PyUnit there's a method which compares dictionaries beautifully. I tested it using the following two dictionaries, and it does exactly what you're looking for.

d1 = {1: "value1",
      2: [{"subKey1":"subValue1",
           "subKey2":"subValue2"}]}
d2 = {1: "value1",
      2: [{"subKey2":"subValue2",
           "subKey1": "subValue1"}]
      }


def assertDictEqual(self, d1, d2, msg=None):
        self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
        self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')

        if d1 != d2:
            standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
            diff = ('\n' + '\n'.join(difflib.ndiff(
                           pprint.pformat(d1).splitlines(),
                           pprint.pformat(d2).splitlines())))
            standardMsg = self._truncateMessage(standardMsg, diff)
            self.fail(self._formatMessage(msg, standardMsg))

I'm not recommending importing unittest into your production code. My thought is the source in PyUnit could be re-tooled to run in production. It uses pprint which "pretty prints" the dictionaries. Seems pretty easy to adapt this code to be "production ready".

答案 20 :(得分:1)

>>> hash_1
{'a': 'foo', 'b': 'bar'}
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_1 = set (hash_1.iteritems())
>>> set_1
set([('a', 'foo'), ('b', 'bar')])
>>> set_2 = set (hash_2.iteritems())
>>> set_2
set([('a', 'foo'), ('b', 'bar')])
>>> len (set_1.difference(set_2))
0
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...    print "The two hashes match."
...
The two hashes match.
>>> hash_2['c'] = 'baz'
>>> hash_2
{'a': 'foo', 'c': 'baz', 'b': 'bar'}
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
>>>
>>> hash_2.pop('c')
'baz'

这是另一种选择:

>>> id(hash_1)
140640738806240
>>> id(hash_2)
140640738994848

所以你看到两个id是不同的。但是rich comparison operators似乎可以解决问题:

>>> hash_1 == hash_2
True
>>>
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_2 = set (hash_2.iteritems())
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
The two hashes match.
>>>

答案 21 :(得分:0)

这是我的答案,请使用recursize方式:

def dict_equals(da, db):
    if not isinstance(da, dict) or not isinstance(db, dict):
        return False
    if len(da) != len(db):
        return False
    for da_key in da:
        if da_key not in db:
            return False
        if not isinstance(db[da_key], type(da[da_key])):
            return False
        if isinstance(da[da_key], dict):
            res = dict_equals(da[da_key], db[da_key])
            if res is False:
                return False
        elif da[da_key] != db[da_key]:
            return False
    return True

a = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
b = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
print dict_equals(a, b)

希望有帮助!

答案 22 :(得分:0)

如今,与==进行简单比较就足够了(python 3.8)。即使您以不同的顺序声明相同的字典(最后一个示例)。

<form flex="100" ng-if="secretaryFound" name="secFoundedForm" id="secFoundedFormId">
                    <!-- my required input -->
                    <div class="disabledInputMargin" flex="95" flex-xs="100" layout="row"
                         layout-align="start start">
                        <md-icon class="zeroMargin" style="color:{{DashboardParams.iconColor2}};">
                            person
                        </md-icon>
                        <md-select class="zeroMargin" flex="100" flex-xs="100" required
                                   ng-model="form.workplaceLableId"
                                   name="mahaelekar"
                                   placeholder="{{'WORKPLACE' | translate}}">
                            <md-option ng-repeat="workplace in workplaceLableList"
                                       value="{{workplace.id}}">
                                {{workplace.addressLable}}
                            </md-option>
                        </md-select>
                    </div>                       
</form>
****{{secFoundedForm.$invalid}}***   <!-- this is not show enything -->
<div style="padding: 0">
    <div flex="100"
         layout="row"
         layout-xs="column"
         layout-align="end stretch">
        <!-- my button is below -->
        <md-button ng-if="secretaryFound" ng-click="inviteSecretary();"
                   name="secFoundedFormId"
                   form="secFoundedFormId"
                   style="background-color:{{DashboardParams.iconColor2}};color: white"
                   ng-disabled="secFoundedForm.mahaelekar.$invalid"
                   flex="20" flex-xs="100">
            {{'INVITE' | translate}}
        </md-button>
        <md-button ng-click="backToSecretary();" style="background-color: #9d9d9d;color: white"
                   flex="20" flex-xs="100">
            {{'BACK' | translate}}
        </md-button>
    </div>
</div>
</div>

答案 23 :(得分:0)

对两个字典进行深入比较的最简单方法(也是最强大的方法之一)是将它们以JSON格式序列化,对键进行排序并比较字符串结果:

import json
if json.dumps(x, sort_keys=True) == json.dumps(y, sort_keys=True):
   ... Do something ...

答案 24 :(得分:-1)

>>> x = {'a':1,'b':2,'c':3}
>>> x
{'a': 1, 'b': 2, 'c': 3}

>>> y = {'a':2,'b':4,'c':3}
>>> y
{'a': 2, 'b': 4, 'c': 3}

METHOD 1:

>>> common_item = x.items()&y.items() #using union,x.item() 
>>> common_item
{('c', 3)}

METHOD 2:

 >>> for i in x.items():
        if i in y.items():
           print('true')
        else:
           print('false')


false
false
true

答案 25 :(得分:-6)

import json

if json.dumps(dict1) == json.dumps(dict2):
    print("Equal")