带有列表自定义相等性检查的字典

时间:2018-08-14 11:52:56

标签: python python-3.x pytest

说,我有两个列表:

a = [1,2,3]b = [2,3,1]

如果我执行a == b,它将返回False

如果我选中sorted(a) == sorted(b),它将返回True

现在,我有两个对象:

obj1 = {'a': 1, 'b': 2, 'c': [1, 2]}obj2 = {'b': 2, 'a': 1, 'c': [1, 2]}

obj1 == obj2为True,与键的顺序无关。

但是如果obj2 = {'b': 2, 'a': 1, 'c': [2, 1]}

我如何测试平等性?显然,obj1 == obj2返回False。 sorted(obj1)将具有['a', 'b', 'c'],因此sorted(obj1) == sorted(obj2)是一种浪费检查。

我可能应该重写该对象的相等方法,或者使用一些库。是,有什么方法可以编写用于深度平等的惯用python代码?

2 个答案:

答案 0 :(得分:6)

sort字典中的每个元素是否为list类型,然后进行比较

>>> def sorted_element_dict(d):
...     return {k:sorted(v) if isinstance(v, list) else v for k,v in d.items()}
...
>>> sorted_element_dict(obj1) == sorted_element_dict(obj2)
True

答案 1 :(得分:1)

如果您只对相等性检查感兴趣,请考虑使用all。您可以将自定义比较器应用于所有字典值:

def check_equal(d1, d2):
    if d1.keys() != d2.keys():
        return False
    return all(sorted(v) == sorted(d2[k]) if isinstance(v, list) else v == d2[k] for k, v in d1.items())

一种更优雅的方法可能是将比较器分解为一个单独的函数,并检查更一般的内容,例如collections.abc.Sequence

def check_equal(d1, d2):
    if d1.keys() != d2.keys():
        return False
    def cmp(v1, v2):
        if isinstance(v1, Sequence) and isinstance(v2, sequence):
            return sorted(v1) == sorted(v2)
        return v1 == v2
    return all(cmp(v, d2[k]) for k, v in d1.items())

这具有存储所有中间分类产品的优势。另一方面,如果您需要经常进行比较,则最好在使用常规==之前先对字典进行转换:

def normalize(d):
    for k, v in d.items():
        if isinstance(v, Sequence):
            d[k] = sorted(v)

请注意,我在这里使用循环而不是理解。这样,您的字典就可以进行原位转换,而不是分配整个新的哈希表。