比较Python中的两个词典

use*_*312 222 python comparison dictionary

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

>>> x = dict(a=1, b=2)
>>> y = dict(a=2, b=2)
Run Code Online (Sandbox Code Playgroud)

现在,我想比较每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
Run Code Online (Sandbox Code Playgroud)

它是有效的,因为tuple返回然后比较相等.

我的问题:

它是否正确?有更好的方法吗?更好的不是速度,我说的是代码优雅.

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

Joc*_*zel 164

你想做的只是简单 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))]
Run Code Online (Sandbox Code Playgroud)

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

  • 从Python 3.6开始,dict是开箱即用的. (4认同)
  • 这不适用于嵌套字典。 (3认同)

mou*_*uad 163

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

也许是这样的:

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print len(shared_items)
Run Code Online (Sandbox Code Playgroud)

  • @ribamar的问题是"比较两个字典[...]".上面带有`list`键的'无效dict'是无效的python代码 - dict*keys*必须是不可变的.因此,您不是在比较字典.如果您尝试使用列表作为字典键,则代码将无法运行.您没有要比较的对象.这就像输入`x = dict(23 \; dfg&^*$ ^%$ ^ $%^)`然后抱怨比较如何与字典无关.当然它不会起作用.另一方面,蒂姆的评论是关于可变的"价值观",因此我说这些是不同的问题. (6认同)
  • @Mutant 那是另一个问题。您首先无法使用“list”键创建字典。`x = {[1,2]: 2}` 将失败。该问题已经具有有效的“dicts”。 (2认同)

Dan*_*ers 147

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)
Run Code Online (Sandbox Code Playgroud)

  • 这个实际上在dict中处理可变值! (6认同)
  • @Afflatus - `DataFrame的设计不允许truthy比较(除非它的长度为1),因为它们继承自`numpy.ndarray`.-credit到http://stackoverflow.com/a/33307396/994076 (2认同)

Ped*_*ito 95

dic1 == dic2

python文档:

为了说明这一点,下面的例子都将返回一个字典等于{"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
Run Code Online (Sandbox Code Playgroud)

适用于py2py3.

  • 只需创建2个相等的dics并测试代码. (5认同)
  • 我不同意@ErkinAlpGüney.官方文档显示==确实按值而不是地址来比较字典.https://docs.python.org/2/library/stdtypes.html#mapping-types-dict (4认同)
  • @ankostis:`OrderedDict!= dict` (4认同)
  • 我不同意@ErkinAlpGüney.你能提供证明吗? (3认同)
  • 适用于Python 2.7.13 (3认同)
  • 如果这不是真的,您可以提供输入吗? (2认同)

phi*_*ipp 53

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

unmatched_item = set(dict_1.items()) ^ set(dict_2.items())
len(unmatched_item) # should be 0
Run Code Online (Sandbox Code Playgroud)

^当两个dicts中的dict相同时,XOR运算符()应该消除dict的所有元素.

  • 不幸的是,如果dict中的值是可变的(即不可清除),则这不起作用.(Ex` {'a':{'b':1}}`给出`TypeError:unhashable type:'dict'.) (26认同)

小智 44

只需使用:

assert cmp(dict1, dict2) == 0
Run Code Online (Sandbox Code Playgroud)

  • 我相信这与`dict1 == dict2`相同 (27认同)
  • 对于任何使用Python3.5的人来说,内置的`cmp`已被删除(应该被视为[之前删除](https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons).他们建议的另一种选择:`(a> b) - (a <b)== cmp(a,b)`用于功能等价物(或更好的`__eq__`和`__hash__`) (10认同)
  • 似乎任务不仅是检查两者的内容是否相同,而且还要报告差异 (6认同)
  • @nerdwaller - dicts不是可订购的类型,所以dict_a> dict_b会引发一个`TypeError`:`unorderable types:dict()<dict()` (3认同)
  • @Stefano:好的,我的评论更多是为了在python中进行一般比较(我没有注意实际的答案,我的错误)。 (2认同)

Sum*_*udu 41

由于似乎没有人提及deepdiff,我将在这里添加它只是为了完整性.我发现一般来说获取(嵌套)对象的差异非常方便.

import deepdiff
import json

dict_1 = {
    "a": 1,
    "nested": {
        "b": 1,
    }
}
dict_2 = {
    "a": 2,
    "nested": {
        "b": 2,
    }
}
diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(diff, indent=4))
Run Code Online (Sandbox Code Playgroud)

输出:

{
    "values_changed": {
        "root['a']": {
            "new_value": 2,
            "old_value": 1
        },
        "root['nested']['b']": {
            "new_value": 2,
            "old_value": 1
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:

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

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


但是,为了获取字典的差异,我觉得deepdiff非常方便.

  • 为什么没人提出这个答案呢?我认为这很好. (3认同)
  • 有趣。感谢您的回答。至少对我有用。这个答案需要更多的投票。 (2认同)

小智 9

对两个字典进行深度比较的最简单方法(也是最可靠的方法之一)是以 JSON 格式序列化它们,对键进行排序,然后比较字符串结果:

import json
if json.dumps(x, sort_keys=True) == json.dumps(y, sort_keys=True):
   ... Do something ...
Run Code Online (Sandbox Code Playgroud)


Ale*_*der 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
Run Code Online (Sandbox Code Playgroud)


WoJ*_*WoJ 7

另一种可能性,直到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))
Run Code Online (Sandbox Code Playgroud)

  • @Bruno:引用OP:*"最好不要速度,我说的是代码优雅"* (7认同)
  • @Bruno:优雅是主观的.我可以理解你不喜欢它(可能是downvoted).这与"错误"不同. (7认同)
  • 这是一个很好的答案.``json.dumps(d,sort_keys = True)``会给你规范的JSON,这样你就可以确定两个dict都是等价的.这也取决于你想要实现的目标.只要该值不是JSON可激活的,它就会失败.因为谁说它效率低下,看看ujson项目. (4认同)
  • 将字符串转储为 JSON 后,您可以直接进行比较。散列这两个字符串只是毫无意义的额外复杂性。(此外,这仅在 dict 支持 JSON 的情况下才有效,而这很多不是。) (4认同)
  • 这完全是错误的,仅将数据解析为json确实很慢。然后散列您刚刚创建的那条巨大的碎片就更糟了。你绝对不要那样做 (2认同)
  • 它一点也不优雅,感觉不安全,并且对于一个非常简单的问题来说过于复杂 (2认同)

Yas*_*Yas 6

代码

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
Run Code Online (Sandbox Code Playgroud)

测试

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


sim*_*ick 5

要测试两个字典的键和值是否相等:

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)
Run Code Online (Sandbox Code Playgroud)

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

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]}
Run Code Online (Sandbox Code Playgroud)

你将不得不调用它两次,即

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))
Run Code Online (Sandbox Code Playgroud)


zwe*_*wep 5

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')
Run Code Online (Sandbox Code Playgroud)

对您或其他任何人都可能有用。

编辑:

我已经创建了上面的一个递归版本。在其他答案中还没有看到

def compare_dict(a, b):
    # Compared two dictionaries..
    # Posts things that are not equal..
    res_compare = []
    for k in set(list(a.keys()) + list(b.keys())):
        if isinstance(a[k], dict):
            z0 = compare_dict(a[k], b[k])
        else:
            z0 = a[k] == b[k]

        z0_bool = np.all(z0)
        res_compare.append(z0_bool)
        if not z0_bool:
            print(k, a[k], b[k])
    return np.all(res_compare)
Run Code Online (Sandbox Code Playgroud)

  • 让我们对其进行改进,使其同时起作用。第2行:“对于set(dict1.keys())。union(dict2.keys())中的x1:” (2认同)

Gio*_*olu 5

我正在使用这个在 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

Run Code Online (Sandbox Code Playgroud)

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

希望有帮助。


Bry*_*ant 5

对于Python3:

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

difference_set = data_set_a ^ data_set_b
Run Code Online (Sandbox Code Playgroud)


Neb*_*tic 5

现在与 == 进行简单的比较就足够了(python 3.8)。即使您以不同的顺序比较相同的字典(最后一个例子)。最好的事情是,您不需要第三方软件包来完成此操作。

a = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
b = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}

c = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
d = {'one': 'dog', 'two': 'cat', 'three': 'mouse', 'four': 'fish'}

e = {'one': 'cat', 'two': 'dog', 'three': 'mouse'}
f = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}

g = {'two': 'cat', 'one': 'dog', 'three': 'mouse'}
h = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}


print(a == b) # True
print(c == d) # False
print(e == f) # False
print(g == h) # True
Run Code Online (Sandbox Code Playgroud)