如果我想比较一系列API响应的复杂性(作为解析和验证响应所需努力的代理),是否有任何现有的工具或库可以相当有效地完成这项工作?或者一个简单的代码片段?
理想情况下,它可以打印出一个快速报告,显示整个结构的深度和宽度以及任何其他可能有用的指标。
如果我想比较一系列API响应的复杂性(作为解析和验证响应所需努力的代理),是否有任何现有的工具或库可以相当有效地完成这项工作?或者一个简单的代码片段?
理想情况下,它可以打印出一个快速报告,显示整个结构的深度和宽度以及任何其他可能有用的指标。
{
,}
,[
和 ]
字符的数量。 当然,这只是一种启发式方法;在此方法下,像{ value: "{[}{}][{{}{}]{}{}{}[}}{}{" }
这样的json对象被认为是过于复杂的,即使它的结构非常简单。let guessJsonComplexity = (json, chars='{}[]')) => {
let count = 0;
for (let char in json) if (chars.includes(char)) count++;
return count / (json.length || 1);
};
let isType = (val, Cls) => val != null && val.constructor === Cls;
let getComplexity = (json, d=1.05) => {
// Here `d` is our "depth factor"
return d * (() => {
// Take the log of the length of a String
if (isType(json, String)) return Math.log(json.length);
// Take the log of (the absolute value of) any Number
if (isType(json, Number)) return Math.log(Math.abs(json));
// Booleans always have a complexity of 1
if (isType(json, Boolean)) return 1;
// Arrays are 1 + (average complexity of their child elements)
if (isType(json, Array)) {
let avg = json.reduce((o, v) => o + getComplexity(v, d), 0) / (json.length || 1);
return avg + 1;
}
// Objects are 1 + (average complexity of their keys) + (average complexity of their values)
if (isType(json, Object)) {
// `getComplexity` for Arrays will add 1 twice, so subtract 1 to compensate
return getComplexity(Object.keys(json), d) + getComplexity(Object.values(json), d) - 1;
}
throw new Error(`Couldn't get complexity for ${json.constructor.name}`);
})();
};
console.log('Simple:', getComplexity([ 'very', 'simple' ]));
console.log('Object:', getComplexity({
i: 'am',
some: 'json',
data: 'for',
testing: 'purposes'
}));
console.log('Complex:', getComplexity([
[ 111, 222, 333, 444 ],
[ 'abc', 'def', 'ghi', 'jkl' ],
[ [], [], {}, {}, 'abc', true, false ]
]));
console.log('Deep:', getComplexity([[[[[[ 'hi' ]]]]]]));
如果你想要了解一个大型json对象的子项更详细的信息,你可以对这些子项调用getComplexity
方法。
,
、:
或"
(甚至是序列":
)来确定这些结构内部的属性和元素数量。 - Bergi我使用任意值,但这只是为了给你一个起点。
var data1 = { "a": { "b": 2 }, "c": [{}, {}, { "d": [1, 2, 3] }] }
var data2 = { "a": { "b": 2 }, "c": [{"x":"y","z":[0,1,2,3,4,5,6,7,8,9]}, {}, { "d": [1, 2, 3] }] }
function chkComplexity(obj) {
let complexity = 0;
let depth = 1;
(function calc(obj) {
for (const key of Object.keys(obj)) {
if (typeof obj[key] !== "object") complexity += depth
if (Array.isArray(obj)) {
depth++
complexity += depth * 2
for (const item of obj) {
calc(item)
}
}
if (typeof obj[key] === "object") {
depth++
complexity += depth * 3
calc(obj[key])
}
}
})(obj);
return complexity;
}
console.log(chkComplexity(data1));
console.log(chkComplexity(data2));
depth
设为参数,将 complexity
设为返回值。这样可以正确隔离这些变化的值。目前情况下,您在下降时增加了深度,但在从下降返回后忽略了减少深度,因此您的深度值会错误地向上膨胀。请考虑:[[[1]],2,3]
,2
和 3
应该具有什么深度值? - Segfault
jsonText.length
。非常高效,并且非常有意义 - 大多数JSON解析器都受输入大小和(读取)速度的限制,而不是嵌套深度或其他因素。 - Bergi