javascript - 如何轻松测量 JSON 对象的复杂性?
问题描述
如果我想比较一系列 API 响应的复杂性(作为解析和验证响应可能需要付出多少努力的代理),是否有任何现有的工具或库可以非常有效地做到这一点?还是一段简单的代码?
理想情况下,可以打印出一份快速报告,显示整个结构的深度和宽度,以及任何其他可能有用的指标。
解决方案
启发式方法是简单地计算{
、}
、[
和]
字符的数量。当然,这只是一种启发式;{ value: "{[}{}][{{}{}]{}{}{}[}}{}{" }
在这种方法下,即使它的结构非常简单,像 json 对象也会被认为过于复杂。
let guessJsonComplexity = (json, chars=new Set('{}[]'.split(''))) => {
let count = 0;
for (let char in json) if (chars.has(char)) count++;
return count / (json.length || 1);
};
如果速度非常重要,你会选择这个答案。
如果您想要更简洁的答案,您几乎肯定需要解析 json!
我们也可以考虑另一种方法。考虑为 json 中可能发生的每种可能现象分配一个“复杂度分数”。例如:
- 包含一个字符串
s
;复杂度分数:Math.log(s.length)
- 包括一个数字
n
;复杂度分数:Math.log(n)
- 包含一个布尔值;复杂度得分:1
- 包含一个数组;复杂度分数:元素的平均复杂度 + 1
- 包含一个对象;复杂度分数:值的平均复杂度加上键的平均复杂度 + 1
我们甚至可以挑选出不同的关系,例如“一个对象包含在一个数组中”或“一个数组包含在一个数组中”等,如果我们想认为其中一些关系比其他关系更“复杂”。例如,我们可以说,负数的“复杂性”是正数的两倍,如果这是我们的感受的话。
我们还可以考虑一个“深度因素”,它使元素越深入越重要。
如果我们定义如何对所有这些现象进行评分,我们可以编写一个处理 json 并应用这样一个分数的函数:
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
这些子对象。
推荐阅读
- selinux - 在私有目录下编译 selinux
- reactjs - React 组件,使用嵌套组件访问 this.props
- python - 基于 Django 类的视图:将附加信息传递给下一个视图
- php - Oracle 数据库连接总是错过 DRCP 缓存
- c# - 使用 TFS Rest API 适用于 curl 但不适用于客户端 dotnet 库
- r - SalesforceR:在 R 中为 SalesForce 批量查询启用 PKChunking
- c++ - g ++宏连接与c ++宏连接
- python - 如何使用 Word2Vec 解决 Tensorflow 中的分类问题
- terraform - 将 tfvars 传递给 tf 文件的问题
- vb.net - 如何使用 VB.net 通过循环快速更新 MySQL 表