且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-10-14 19:54:54

如果您希望具有相同元素但顺序不同的两个对象比较相等,那么显而易见的事情就是比较它们的已排序副本 - 例如, 对于由您的 JSON 字符串 ab 表示的字典:

导入jsona = json.loads("""{错误":[{错误":无效",字段":电子邮件"},{"error": "required", "field": "name"}],成功":假}""")b = json.loads("""{成功":错误,错误":[{"error": "required", "field": "name"},{错误":无效",字段":电子邮件"}]}""")

>>>排序(a.items())==排序(b.items())错误的

... 但这不起作用,因为在每种情况下,***字典的 "errors" 项都是一个列表,其中元素的顺序不同,而 sorted() 不会尝试对可迭代对象的***"级别以外的任何内容进行排序.

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

def 排序(对象):如果是实例(对象,字典):返回 sorted((k,ordered(v)) for k, v in obj.items())如果是实例(对象,列表):return sorted(ordered(x) for x in obj)别的:返回对象

如果我们将此函数应用于ab,结果比较相等:

>>>有序(a)==有序(b)真的

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

For example ...

JSON document a:

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

JSON document 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.

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:

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.

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):

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:

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