一尘不染

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

django

我如何测试python中两个JSON对象是否相等,而忽略列表的顺序?

例如 …

JSON文档a:

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

JSON文档b:

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

a并且b应该比较相等,即使"errors"列表的顺序不同。


阅读 459

收藏
2020-03-27

共1个答案

一尘不染

如果你想要两个具有相同元素但顺序不同的对象相等,那么显而易见的事情是比较它们的排序后的副本-例如,以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

…但这是行不通的,因为在每种情况下,”errors”顶层dict的项都是具有相同元素的列表,但是顺序不同,并且sorted()除了“ top”级别的内容外,不会尝试对任何内容进行排序一个可迭代的。

为了解决这个问题,我们可以定义一个ordered函数,该函数将对找到的所有列表进行递归排序(并将字典转换(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

如果我们将此功能应用于a和b,结果比较相等:

>>> ordered(a) == ordered(b)
True
2020-03-27