javascript - 将包含 JSON 对象的 JSON 对象缩减为 [Path, Value] 形式的数组
问题描述
我正在尝试将嵌套对象、数组和字符串的 JSON 对象减少为路径和值的单个数组。
预期输入:
appleObjects = {
'apples': {
'colors': ['red', 'green', 'yellow'],
'owner': 'Person1',
'types': [
{name: 'fuji', flavor: 'good'}
]
},
'pears': {
'colors': ['red', 'green', 'yellow'],
'owner': 'Person1',
'types': [
{name: 'small', flavor: 'surprising'},
{name: 'large', flavor: 'bold'}
]
}
}
预期输出:
appleValues = [
{path: 'apples.colors', value: 'red'},
{path: 'apples.colors', value: 'green'},
{path: 'apples.colors', value: 'yellow'},
{path: 'apples.owner', value: 'Person1'},
{path: 'apples.types', value: {name: 'fuji', flavor: 'sweet?'}}
...
]
到目前为止,我正在努力使用嵌套的 reduce 函数和/或递归,但由于它是在一个 Web 应用程序中,我想知道是否有更有效的方法,甚至是一个已经做类似事情的库。
这是我目前正在使用的。目前 react 抱怨递归太多,所以很明显这不是实现这一目标的最佳方法:
myReducer = (p, obj) => {
Object.entries(obj ?? []).reduce((acc, currVal, currIdx) => {
if(typeof currVal === undefined) {
return acc
}
if(typeof currVal === "string") {
return {
basePath: acc.basePath,
outputArr: acc.outputArr.push({
path: acc.basePath + '.' + currVal[0],
value: currVal[1]
})
}
}
if(typeof currVal === "object") {
return {
basePath: acc.basePath,
outputArr: acc.outputArr.concat(this.myReducer(acc.basePath + '.' + currVal[0], currVal[1]))
}
}
return acc
}, {basePath: p, outputArr: []})
}
getArrayOfApplesValues = () => {
const {
applesObjects
} = this.state
if (applesObjects === null) return []
Object.entries(applesObjects).reduce((acc, currVal, currIdx) => {
if(typeof currVal[1] === "object") {
return {
path: acc.basePath,
outputArr: acc.outputArr.concat(this.myReducer (acc.basePath + '.' + currVal[0], currVal[1]))
}
}
return acc
}, {basePath: '', outputArr: []})
}
请原谅我在示例中缺乏苹果知识。
解决方案
而不是运行reduce
你必须递归地运行你的代码并尝试使用以下函数将你的对象展平为一个数组:
let appleObjects = {
'apples': {
'colors': ['red', 'green', 'yellow'],
'owner': 'Person1',
'types': [
{name: 'fuji', flavor: 'good'}
]
},
'pears': {
'colors': ['red', 'green', 'yellow'],
'owner': 'Person1',
'types': [
{name: 'small', flavor: 'surprising'},
{name: 'large', flavor: 'bold'}
]
}
};
let flatten = (obj, prefix, result) => {
result = result || [];
for(let key of Object.keys(obj)){
let keyExpr = prefix ? `${prefix}.${key}` : `${key}`;
if(Array.isArray(obj[key])){
obj[key].forEach(x => result.push({path: keyExpr, value: x}));
}
else if(typeof obj[key] === "object"){
flatten(obj[key], keyExpr, result);
}
else {
result.push({path: keyExpr, value: obj[key]})
}
}
return result;
}
let result = flatten(appleObjects);
console.log(result);
推荐阅读
- python - 在 Pygame 中,组不闪烁到屏幕上
- flutter - Dart 中的 RSA 实现
- python - 递归函数计算概率
- python - 无法在python中读取文本文件
- rest - 您是否必须指定所有路由以符合rest api?
- column-count - 为什么我的列数不能在 chrome 和 safari 中正常工作?
- unity3d - Unity 2D 自动滚动射击游戏
- php - 没有语法错误仍然没有写入php文件
- javascript - 在 VUE 中向另一个 URL 或选项卡发送/接收消息
- google-sheets - 查询公式不适用于错误 AVG_SUM_ONLY_NUMERIC