80 python django comparison json
如何在python中测试两个JSON对象是否相等,忽略列表的顺序?
例如 ...
JSON文档a:
{
"errors": [
{"error": "invalid", "field": "email"},
{"error": "required", "field": "name"}
],
"success": false
}
Run Code Online (Sandbox Code Playgroud)
JSON文件b:
{
"success": false,
"errors": [
{"error": "required", "field": "name"},
{"error": "invalid", "field": "email"}
]
}
Run Code Online (Sandbox Code Playgroud)
a并且b应该比较相等,即使"errors"列表的顺序不同.
Zer*_*eus 114
如果你想要两个具有相同元素但顺序不同的对象进行比较,那么显而易见的事情就是比较它们的排序副本 - 例如,对于由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"}
]
}
""")
Run Code Online (Sandbox Code Playgroud)
>>> sorted(a.items()) == sorted(b.items())
False
Run Code Online (Sandbox Code Playgroud)
...但是这不起作用,因为在每种情况下,"errors"顶级字典的项目是具有不同顺序的相同元素的列表,并且sorted()不会尝试排序除"顶部"级别之外的任何内容一个可迭代的.
为了解决这个问题,我们可以定义一个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
Run Code Online (Sandbox Code Playgroud)
如果我们将此函数应用于a和b,结果比较相等:
>>> ordered(a) == ordered(b)
True
Run Code Online (Sandbox Code Playgroud)
stp*_*tpk 32
另一种方法是使用json.dumps(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
Run Code Online (Sandbox Code Playgroud)
这适用于嵌套字典和列表.
fal*_*tru 15
解码它们并将它们作为mgilson评论进行比较.
只要键和值匹配,顺序对字典无关紧要.(字典在Python中没有顺序)
>>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1}
True
Run Code Online (Sandbox Code Playgroud)
但是顺序在列表中很重要; 排序将解决列表的问题.
>>> [1, 2] == [2, 1]
False
>>> [1, 2] == sorted([2, 1])
True
Run Code Online (Sandbox Code Playgroud)
>>> 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
Run Code Online (Sandbox Code Playgroud)
以上示例将适用于问题中的JSON.有关一般解决方案,请参阅Zero Piraeus的答案.
更新:请参阅https://eggachecat.github.io/jycm-json-diff-viewer/进行现场演示!现在它有一个 JS 原生实现。
隶属关系:我是该库的作者。
是的!你可以使用jycm
from jycm.helper import make_ignore_order_func
from jycm.jycm import YouchamaJsonDiffer
a = {
"errors": [
{"error": "invalid", "field": "email"},
{"error": "required", "field": "name"}
],
"success": False
}
b = {
"success": False,
"errors": [
{"error": "required", "field": "name"},
{"error": "invalid", "field": "email"}
]
}
ycm = YouchamaJsonDiffer(a, b, ignore_order_func=make_ignore_order_func([
"^errors",
]))
ycm.diff()
assert ycm.to_dict(no_pairs=True) == {} # aka no diff
Run Code Online (Sandbox Code Playgroud)
对于更复杂的示例(深层结构中的值变化)
from jycm.helper import make_ignore_order_func
from jycm.jycm import YouchamaJsonDiffer
a = {
"errors": [
{"error": "invalid", "field": "email"},
{"error": "required", "field": "name"}
],
"success": True
}
b = {
"success": False,
"errors": [
{"error": "required", "field": "name-1"},
{"error": "invalid", "field": "email"}
]
}
ycm = YouchamaJsonDiffer(a, b, ignore_order_func=make_ignore_order_func([
"^errors",
]))
ycm.diff()
assert ycm.to_dict() == {
'just4vis:pairs': [
{'left': 'invalid', 'right': 'invalid', 'left_path': 'errors->[0]->error', 'right_path': 'errors->[1]->error'},
{'left': {'error': 'invalid', 'field': 'email'}, 'right': {'error': 'invalid', 'field': 'email'},
'left_path': 'errors->[0]', 'right_path': 'errors->[1]'},
{'left': 'email', 'right': 'email', 'left_path': 'errors->[0]->field', 'right_path': 'errors->[1]->field'},
{'left': {'error': 'invalid', 'field': 'email'}, 'right': {'error': 'invalid', 'field': 'email'},
'left_path': 'errors->[0]', 'right_path': 'errors->[1]'},
{'left': 'required', 'right': 'required', 'left_path': 'errors->[1]->error',
'right_path': 'errors->[0]->error'},
{'left': {'error': 'required', 'field': 'name'}, 'right': {'error': 'required', 'field': 'name-1'},
'left_path': 'errors->[1]', 'right_path': 'errors->[0]'},
{'left': 'name', 'right': 'name-1', 'left_path': 'errors->[1]->field', 'right_path': 'errors->[0]->field'},
{'left': {'error': 'required', 'field': 'name'}, 'right': {'error': 'required', 'field': 'name-1'},
'left_path': 'errors->[1]', 'right_path': 'errors->[0]'},
{'left': {'error': 'required', 'field': 'name'}, 'right': {'error': 'required', 'field': 'name-1'},
'left_path': 'errors->[1]', 'right_path': 'errors->[0]'}
],
'value_changes': [
{'left': 'name', 'right': 'name-1', 'left_path': 'errors->[1]->field', 'right_path': 'errors->[0]->field',
'old': 'name', 'new': 'name-1'},
{'left': True, 'right': False, 'left_path': 'success', 'right_path': 'success', 'old': True, 'new': False}
]
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
92405 次 |
| 最近记录: |