如何用相同的元素以不同的顺序比较两个JSON对象?

时间:2022-06-29 16:14:28

How can I test whether two JSON objects are equal in python, disregarding the order of lists?

如何测试两个JSON对象在python中是否相等,而不考虑列表的顺序?

For example ...

例如……

JSON document a:

JSON文档:

{
    "errors": [
        {"error": "invalid", "field": "email"},
        {"error": "required", "field": "name"}
    ],
    "success": false
}

JSON document b:

JSON文档b:

{
    "success": false,
    "errors": [
        {"error": "required", "field": "name"},
        {"error": "invalid", "field": "email"}
    ]
}

a and b should compare equal, even though the order of the "errors" lists are different.

a和b应该比较相等,即使“错误”列表的顺序不同。

3 个解决方案

#1


72  

If you want two objects with the same elements but in a different order to compare equal, then the obvious thing to do is compare sorted copies of them - for instance, for the dictionaries represented by your JSON strings a and b:

如果您希望两个对象具有相同的元素,但以不同的顺序进行比较,那么显然要做的事情是比较它们的已排序副本——例如,对于由JSON字符串a和b表示的字典:

import json

a = json.loads("""
{
    "errors": [
        {"error": "invalid", "field": "email"},
        {"error": "required", "field": "name"}
    ],
    "success": false
}
""")

b = json.loads("""
{
    "success": false,
    "errors": [
        {"error": "required", "field": "name"},
        {"error": "invalid", "field": "email"}
    ]
}
""")
>>> sorted(a.items()) == sorted(b.items())
False

... but that doesn't work, because in each case, the "errors" item of the top-level dict is a list with the same elements in a different order, and sorted() doesn't try to sort anything except the "top" level of an iterable.

…但这是行不通的,因为在每种情况下,*词典的“error”项都是一个具有相同元素的列表,其顺序不同,sort()除了可迭代的“top”级别之外,不尝试对任何内容进行排序。

To fix that, we can define an ordered function which will recursively sort any lists it finds (and convert dictionaries to lists of (key, value) pairs so that they're orderable):

为了解决这个问题,我们可以定义一个有序函数,它将对它找到的任何列表进行递归排序(并将字典转换为(key, value)对的列表,以便它们是有序的):

def ordered(obj):
    if isinstance(obj, dict):
        return sorted((k, ordered(v)) for k, v in obj.items())
    if isinstance(obj, list):
        return sorted(ordered(x) for x in obj)
    else:
        return obj

If we apply this function to a and b, the results compare equal:

如果我们把这个函数应用于a和b,结果是相等的:

>>> ordered(a) == ordered(b)
True

#2


15  

Another way could be to use json.dumps(X, sort_keys=True) option:

另一种方法是使用json。转储(X,sort_keys = True)选择:

import json
a, b = json.dumps(a, sort_keys=True), json.dumps(b, sort_keys=True)
a == b # a normal string comparison

This works for nested dictionaries and lists.

这适用于嵌套字典和列表。

#3


11  

Decode them and compare them as mgilson comment.

对它们进行解码,并将其与mgilson的评论进行比较。

Order does not matter for dictionary as long as the keys, and values matches. (Dictionary has no order in Python)

只要键和值匹配,字典的顺序就不重要。(Python中字典没有顺序)

>>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1}
True

But order is important in list; sorting will solve the problem for the lists.

但是顺序在列表中很重要;排序将解决列表的问题。

>>> [1, 2] == [2, 1]
False
>>> [1, 2] == sorted([2, 1])
True

>>> a = '{"errors": [{"error": "invalid", "field": "email"}, {"error": "required", "field": "name"}], "success": false}'
>>> b = '{"errors": [{"error": "required", "field": "name"}, {"error": "invalid", "field": "email"}], "success": false}'
>>> a, b = json.loads(a), json.loads(b)
>>> a['errors'].sort()
>>> b['errors'].sort()
>>> a == b
True

Above example will work for the JSON in the question. For general solution, see Zero Piraeus's answer.

上面的示例将适用于问题中的JSON。对于一般解,请参见零比雷埃夫斯的答案。

#1


72  

If you want two objects with the same elements but in a different order to compare equal, then the obvious thing to do is compare sorted copies of them - for instance, for the dictionaries represented by your JSON strings a and b:

如果您希望两个对象具有相同的元素,但以不同的顺序进行比较,那么显然要做的事情是比较它们的已排序副本——例如,对于由JSON字符串a和b表示的字典:

import json

a = json.loads("""
{
    "errors": [
        {"error": "invalid", "field": "email"},
        {"error": "required", "field": "name"}
    ],
    "success": false
}
""")

b = json.loads("""
{
    "success": false,
    "errors": [
        {"error": "required", "field": "name"},
        {"error": "invalid", "field": "email"}
    ]
}
""")
>>> sorted(a.items()) == sorted(b.items())
False

... but that doesn't work, because in each case, the "errors" item of the top-level dict is a list with the same elements in a different order, and sorted() doesn't try to sort anything except the "top" level of an iterable.

…但这是行不通的,因为在每种情况下,*词典的“error”项都是一个具有相同元素的列表,其顺序不同,sort()除了可迭代的“top”级别之外,不尝试对任何内容进行排序。

To fix that, we can define an ordered function which will recursively sort any lists it finds (and convert dictionaries to lists of (key, value) pairs so that they're orderable):

为了解决这个问题,我们可以定义一个有序函数,它将对它找到的任何列表进行递归排序(并将字典转换为(key, value)对的列表,以便它们是有序的):

def ordered(obj):
    if isinstance(obj, dict):
        return sorted((k, ordered(v)) for k, v in obj.items())
    if isinstance(obj, list):
        return sorted(ordered(x) for x in obj)
    else:
        return obj

If we apply this function to a and b, the results compare equal:

如果我们把这个函数应用于a和b,结果是相等的:

>>> ordered(a) == ordered(b)
True

#2


15  

Another way could be to use json.dumps(X, sort_keys=True) option:

另一种方法是使用json。转储(X,sort_keys = True)选择:

import json
a, b = json.dumps(a, sort_keys=True), json.dumps(b, sort_keys=True)
a == b # a normal string comparison

This works for nested dictionaries and lists.

这适用于嵌套字典和列表。

#3


11  

Decode them and compare them as mgilson comment.

对它们进行解码,并将其与mgilson的评论进行比较。

Order does not matter for dictionary as long as the keys, and values matches. (Dictionary has no order in Python)

只要键和值匹配,字典的顺序就不重要。(Python中字典没有顺序)

>>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1}
True

But order is important in list; sorting will solve the problem for the lists.

但是顺序在列表中很重要;排序将解决列表的问题。

>>> [1, 2] == [2, 1]
False
>>> [1, 2] == sorted([2, 1])
True

>>> a = '{"errors": [{"error": "invalid", "field": "email"}, {"error": "required", "field": "name"}], "success": false}'
>>> b = '{"errors": [{"error": "required", "field": "name"}, {"error": "invalid", "field": "email"}], "success": false}'
>>> a, b = json.loads(a), json.loads(b)
>>> a['errors'].sort()
>>> b['errors'].sort()
>>> a == b
True

Above example will work for the JSON in the question. For general solution, see Zero Piraeus's answer.

上面的示例将适用于问题中的JSON。对于一般解,请参见零比雷埃夫斯的答案。