当前位置:网站首页>JSON data comparer
JSON data comparer
2022-07-01 05:35:00 【hotswwkyo】
json Data comparator
Not only support for json object 、 Direct comparison of arrays , It also supports nested complex json Direct comparison of objects and arrays .
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
''' @Author: Si Wenwei '''
import json
class JSONCheckpoint(object):
"""JSON Format data checkpoints , Supports two complex JSON Direct comparison JSON Write the data as the name / It's worth it . name / The value consists of the field name , Followed by a colon and a value :{ "name":"Bill Gates" } stay JSON in , The value must be one of the following data types : character string Numbers object (JSON object ) Array Boolean null Simple usage: alist = [{ "status": "success", "data": { "44131521": [{ "joinno": "201812120000013935", "zzbcode": "44131521", }, { "joinno": "201812120000013936", "zzbcode": "44131521", }, { "joinno": "201812120000013937", "zzbcode": "44131521", }] } }] elist = [{ "status": "success", "data": { "44131521": [{ "joinno": "201812120000013937", "zzbcode": "44131521" }, { "joinno": "201812120000013935", "zzbcode": "44131521", }, { "joinno": "201812120000013936", "zzbcode": "44131521", }] } }] JSONCheckpoint().test(alist, elist, False) """
CONVERT_JSON_TEXT_TO_PYTHON_OBJECT = True
def to_py_obj(self, json_text):
return json.loads(json_text)
def test(self, actual, expected, convert=CONVERT_JSON_TEXT_TO_PYTHON_OBJECT, ignore_position=True, list_strict=True, dict_strict=True):
""" Compare two objects for equality Args: - actual: actual - expected: expect - ignore_position: Controls whether to call the ignore position comparison function or the exact equality comparison function True - Ignore location False - Completely equal - list_strict: ignore_position by True When , This parameter makes sense - dict_strict: ignore_position by True When , This parameter makes sense """
if convert == self.CONVERT_JSON_TEXT_TO_PYTHON_OBJECT:
expected = self.to_py_obj(expected)
print(self.equals(actual, expected, ignore_position=ignore_position, list_strict=list_strict, dict_strict=dict_strict))
def equals(self, actual, expected, ignore_position=True, list_strict=True, dict_strict=True):
""" Compare two objects for equality Args: - actual: actual - expected: expect - ignore_position: Controls whether to call the ignore position comparison function or the exact equality comparison function True - Ignore location False - Completely equal - list_strict: ignore_position by True When , This parameter makes sense - dict_strict: ignore_position by True When , This parameter makes sense """
if isinstance(expected, (list, tuple)) and isinstance(actual, (list, tuple)):
if ignore_position:
return self.json_array_equals_ignore_position(actual, expected, list_strict=list_strict, dict_strict=dict_strict)
else:
return self.json_array_equals(actual, expected)
elif isinstance(expected, dict) and isinstance(actual, dict):
if ignore_position:
return self.json_obj_equals_ignore_position(actual, expected, dict_strict=dict_strict, list_strict=list_strict)
else:
return self.json_obj_equals(actual, expected)
elif isinstance(expected, bool) or isinstance(actual, bool): # Either one is bool value , Is to bool Value comparison
return self.all_is_same_bool_value(actual, expected)
elif expected is None or actual is None: # Either one is None value , Is to None Compare
return self.all_is_none(actual, expected)
else:
return actual == expected
def _group(self, dlist):
""" Group child elements of a list by data type , The grouping rules are as follows : - None Divided into one group - Boolean value Divided into one group - character string integer floating-point Divided into one group - list Yuan Zu Group together - Dictionary types are grouped - In addition to the above, other types are divided into a group """
others = []
sublists = []
subdicts = []
nonelist = []
boollist = []
str_int_float = []
for one in dlist:
if one is None:
nonelist.append(one)
elif isinstance(one, bool):
boollist.append(one)
elif isinstance(one, (str, int, float)):
str_int_float.append(one)
elif isinstance(one, (list, tuple)):
sublists.append(one)
elif isinstance(one, dict):
subdicts.append(one)
else:
others.append(one)
return nonelist, boollist, str_int_float, sublists, subdicts, others
def json_obj_equals_ignore_position(self, adict, edict, dict_strict=True, list_strict=True):
"""json Object type data is equivalent to python Dictionary , Compare two dictionaries for equality , Support nested dictionaries and list primitives Args: - adict Actual Dictionary - edict Expected dictionary - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) Useage: self.json_obj_equals_ignore_position({"a":1,"b":2}, {"a":1,"b":2}) >>> True self.json_obj_equals_ignore_position({"a":1,"b":2}, {"a":1}, dict_strict=False) >>> True self.json_obj_equals_ignore_position({"a":1,"b":{"c":3}}, {"a":1,"b":{"c":3}}) >>> True """
akeys = adict.keys()
ekeys = edict.keys()
if dict_strict:
if len(akeys) != len(ekeys):
return False
for k in ekeys:
if k not in akeys:
return False
else:
v1 = adict[k]
v2 = edict[k]
if isinstance(v1, (list, tuple)) and isinstance(v2, (list, tuple)):
if not self.json_array_equals_ignore_position(v1, v2, list_strict=list_strict, dict_strict=dict_strict):
return False
elif isinstance(v1, dict) and isinstance(v2, dict):
subresult = self.json_obj_equals_ignore_position(v1, v2, dict_strict=dict_strict, list_strict=list_strict)
if not subresult:
return False
elif isinstance(v1, bool) or isinstance(v2, bool): # Either one is bool value , Is to bool Value comparison
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # Either one is None value , Is to None Compare
if not self.all_is_none(v1, v2):
return False
else:
if v1 != v2:
return False
return True
def _none_equals(self, a_nonelist, e_nonelist, strict=True):
is_equals = True
if strict:
len1 = len(a_nonelist)
len2 = len(e_nonelist)
used = []
if len1 == len2:
for val in e_nonelist:
if val not in used:
used.append(val)
count1 = a_nonelist.count(val)
count2 = e_nonelist.count(val)
if count1 != count2:
is_equals = False
break
else:
is_equals = False
else:
foundindexs = []
for e_none in e_nonelist:
found = False
for i, a_none in enumerate(a_nonelist):
if i not in foundindexs:
if e_none is a_none:
foundindexs.append(i)
found = True
if not found:
is_equals = False
break
return is_equals
_bool_equals = _none_equals
def _basic_data_equals(self, a_data, e_data, strict=True):
is_equals = True
if strict:
used = []
len1 = len(a_data)
len2 = len(e_data)
if len1 == len2:
for val in a_data:
if val not in used:
used.append(val)
count1 = a_data.count(val)
count2 = e_data.count(val)
if count1 != count2:
is_equals = False
break
else:
is_equals = False
else:
found_indexs = []
for e_val in e_data:
found = False
for i, a_val in enumerate(a_data):
if i not in found_indexs:
if e_val == a_val:
found_indexs.append(i)
found = True
break
if not found:
is_equals = False
break
return is_equals
_unknow_type_data_equals = _basic_data_equals
@staticmethod
def is_all_empty_objs(*objs):
empty = True
for obj in objs:
if len(obj) >= 1:
empty = False
break
return empty
@staticmethod
def all_is_same_bool_value(*objs):
truelist = []
falselist = []
non_bool = False
for obj in objs:
if isinstance(obj, bool):
if obj is True:
truelist.append(obj)
else:
falselist.append(obj)
else:
non_bool = True
break
if non_bool:
return False # any object is not boolean
else:
if len(objs) == len(truelist) or len(objs) == len(falselist):
return True
else:
return False
@staticmethod
def all_is_none(*objs):
nonelist = []
for obj in objs:
if obj is None:
nonelist.append(obj)
else:
break
if len(nonelist) == len(objs):
return True
else:
return False
def _json_array_equals_ignore_position(self, source, expected, list_strict=True, dict_strict=True):
""" Args: - source In the actual list, all the sub elements of the list make up the list - expected The expected list consists of all the child elements of the list - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal """
len1 = len(source)
len2 = len(expected)
founds = []
for a_val in source:
a_len = len(a_val)
for e_val in expected:
e_len = len(e_val)
if a_len == e_len:
if self.json_array_equals_ignore_position(a_val, e_val, list_strict=list_strict, dict_strict=dict_strict):
founds.append(a_val)
break
flen = len(founds)
return (len1 == len2) and (len2 == flen)
def _dictlist_check(self, source, expected, list_strict=True, dict_strict=True):
""" Args: - source In the actual list, all the sub elements of the dictionary make up the list - expected The expected list consists of all the sub elements of the dictionary - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) """
len1 = len(source)
len2 = len(expected)
if len1 == len2:
used_indexs = []
not_found_in_source = []
for edict in expected:
found = False
for index, sdict in enumerate(source):
if index in used_indexs:
continue
if self.json_obj_equals_ignore_position(sdict, edict, dict_strict=dict_strict, list_strict=list_strict):
found = True
used_indexs.append(index)
break
if not found:
not_found_in_source.append(edict)
break
if not_found_in_source:
return False
else:
return True
else:
return False
def printjson(self, *obj, **config):
msg = config.get('msg', '')
printable = [json.dumps(o, ensure_ascii=False) for o in obj]
print(msg + '\n'.join(printable))
def json_array_equals_ignore_position(self, alist, elist, list_strict=True, dict_strict=True):
""" Ignore list element position , Compare two lists for equality , Support that list elements can be nested data Args: - alist Actual list - elist Expected list - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) """
if list_strict:
if len(alist) != len(elist):
return False
a_nonelist, a_boollist, a_basedata, a_array_list, a_dict_list, a_other_list = self._group(alist)
e_nonelist, e_boollist, e_basedata, e_array_list, e_dict_list, e_other_list = self._group(elist)
noneresult = self._none_equals(a_nonelist, e_nonelist, list_strict)
boolresult = self._bool_equals(a_boollist, e_boollist, list_strict)
bresult = self._basic_data_equals(a_basedata, e_basedata, list_strict)
uresult = self._unknow_type_data_equals(a_other_list, e_other_list, list_strict)
r1 = noneresult and boolresult and bresult and uresult
empty = self.is_all_empty_objs(a_array_list, a_dict_list, e_array_list, e_dict_list)
if (not r1) or empty:
return r1
r2 = self._json_array_equals_ignore_position(a_array_list, e_array_list, list_strict=list_strict, dict_strict=dict_strict)
r3 = self._dictlist_check(a_dict_list, e_dict_list, dict_strict=dict_strict, list_strict=list_strict)
return r1 and r2 and r3
def json_obj_equals(self, adict, edict):
""" Whether two json Whether the objects are exactly equal Args: - adict Actual Dictionary - edict Expected dictionary Useage: self.json_obj_equals({"a":1,"b":2}, {"a":1,"b":2}) >>> True self.json_obj_equals({"a":1,"b":2}, {"a":1}) >>> False self.json_obj_equals({"a":1,"b":{"c":3}}, {"a":1,"b":{"c":3}}) >>> True """
akeys = adict.keys()
ekeys = edict.keys()
if len(akeys) != len(ekeys):
return False
for k in ekeys:
if k not in akeys:
return False
else:
v1 = adict[k]
v2 = edict[k]
if isinstance(v1, (list, tuple)) and isinstance(v2, (list, tuple)):
if not self.json_array_equals(v1, v2):
return False
elif isinstance(v1, dict) and isinstance(v2, dict):
subresult = self.json_obj_equals(v1, v2)
if not subresult:
return False
elif isinstance(v1, bool) or isinstance(v2, bool): # Either one is bool value , Is to bool Value comparison
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # Either one is None value , Is to None Compare
if not self.all_is_none(v1, v2):
return False
else:
if v1 != v2:
return False
return True
def json_array_equals(self, alist, elist):
""" Judge json Whether the arrays are exactly equal , That is, the number of elements of the two arrays and the element values at the same position must be exactly the same , It's the same Args: - alist Actual list - elist Expected list """
alen = len(alist)
elen = len(elist)
if alen != elen:
return False
for i, v1 in enumerate(elist):
v2 = alist[i]
if isinstance(v1, (list, tuple)) and isinstance(v2, (list, tuple)):
if not self.json_array_equals(v2, v1):
return False
elif isinstance(v1, dict) and isinstance(v2, dict):
if not self.json_obj_equals(v2, v1):
return False
elif isinstance(v1, bool) or isinstance(v2, bool): # Either one is bool value , Is to bool Value comparison
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # Either one is None value , Is to None Compare
if not self.all_is_none(v1, v2):
return False
else:
if v1 != v2:
return False
return True
class Age(object):
def __init__(self, number):
self._number = number
def __eq__(self, other):
return self._number == other._number
if __name__ == "__main__":
checker = JSONCheckpoint()
# ignore_position=False More equal ( Exactly the same )
# That is, the two values must be exactly equal , If the two values are lists or dictionaries , Then the number of elements in the list and its nested list and the element value at the same position must be exactly the same ,
# The key values of the dictionary and its nested descendant dictionaries must be exactly the same , Then the two values are equal
a = [1, 2, {
"age": 18}]
b = [1, 2, {
"age": 18}]
checker.test(a, b, False, ignore_position=False)
a = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=False)
# ignore_position=True, list_strict=True, dict_strict=True
# Ignore the position of elements in an array or nested array , The elements of the actual and expected arrays must be exactly the same , The actual and expected dictionary keys must be exactly the same , Is considered equal
a = [1, 2, {
"age": 18}]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=True)
a = {
"age": 18, "friends": [" Xiaohong ", " Xiao Ming "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=True)
# ignore_position=True, list_strict=False, dict_strict=True
# Ignore the position of elements in an array or nested array , The actual array contains exactly the elements of the expected array , The actual and expected dictionary keys must be exactly the same , Is considered equal
a = [1, 2, {
"age": 18}, 3]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=True)
a = {
"age": 18, "friends": [" Xiaohong ", " Xiao Ming ", " Kasumi "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=True)
# ignore_position=True, list_strict=True, dict_strict=False
# Ignore the position of elements in an array or nested array , The elements of the actual and expected arrays must be exactly the same , The actual dictionary contains exactly the key values of the expected dictionary , Is considered equal
a = [1, 2, {
"age": 18, "name": " Xiao Xuan "}]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=False)
a = {
"age": 18, "name": " corolla ", "friends": [" Xiaohong ", " Xiao Ming "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=False)
# ignore_position=True, list_strict=False, dict_strict=False
# Ignore the position of elements in an array or nested array , The actual array contains exactly the elements of the expected array , The actual dictionary contains exactly the key values of the expected dictionary , Is considered equal
a = [1, 2, {
"age": 18, "name": " Xiao Xuan "}, 3, 2, False, False, None, None, Age(1), Age(1)]
b = [2, {
"age": 18}, 1, 2, False, None, Age(1)]
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=False)
a = {
"age": 18, "name": " corolla ", "friends": [" Xiaohong ", " Xiao Ming ", " Kasumi "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=False)
边栏推荐
- Redis数据库的部署及常用命令
- 新手在挖财开通证券账户安全吗?
- JDBC common interview questions
- 教务管理系统(免费源码获取)
- C WPF uses dockpanel to realize screenshot box
- Worried about infringement? Must share copyrightless materials on the website. Don't worry about the lack of materials for video clips
- QT等待框制作
- 如何选择导电滑环材料
- Thread process foundation of JUC
- Lock free concurrency of JUC (leguan lock)
猜你喜欢

boot+jsp的高校社团管理系统(附源码下载链接)

Use and principle of reentrantlock

教务管理系统(免费源码获取)

Cockroachdb: the resistant geo distributed SQL database paper reading notes

Spanner 论文小结

Mathematical knowledge: finding the number of divisors

提高企业产品交付效率系列(1)—— 企业应用一键安装和升级

如何选择导电滑环材料

Practice of combining rook CEPH and rainbow, a cloud native storage solution

Leetcode top 100 question 2 Add two numbers
随机推荐
Fluentd is easy to use. Combined with the rainbow plug-in market, log collection is faster
Usage and principle of synchronized
Set set detailed explanation
Deeply understand the underlying implementation principle of countdownlatch in concurrent programming
More than one file was found with OS independent path ‘lib/armeabi-v7a/libyuv. so‘.
Unity 使用Sqlite
数据治理:元数据管理实施(第四篇)
Mongodb學習篇:安裝後的入門第一課
What things you didn't understand when you were a child and didn't understand until you grew up?
Some common commands of podman
How to meet the requirements of source code confidentiality and source code security management
Spanner 论文小结
Practice of combining rook CEPH and rainbow, a cloud native storage solution
What is the at instruction set often used in the development of IOT devices?
Unity uses SQLite
Printk debugging summary
如何开始学剪辑?零基础详细解析
在Rainbond中一键部署高可用 EMQX 集群
Mongodb学习篇:安装后的入门第一课
Chapitre d'apprentissage mongodb: Introduction à la première leçon après l'installation