首页 > 解决方案 > 将包含 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: []})
  }

请原谅我在示例中缺乏苹果知识。

标签: javascriptjsonreactjsjavascript-objects

解决方案


而不是运行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);


推荐阅读