【问题标题】:Converting nested JSON to flat JSON with TypeScript /JS/RxJS / map/reduce/filter whatever,使用 TypeScript /JS/RxJS / map/reduce/filter 将嵌套 JSON 转换为平面 JSON,
【发布时间】:2016-07-28 13:55:00
【问题描述】:

如果可能的话,如何使用现有的 JS 库(用于 Observables 的 RxJS、Lodash/Underscore/whatever)进行转换(无需复杂的 foreach 循环)

结构如下:

{
    "result": [
        {
            "content": {
                "resources": [
                    {
                        "prop": [
                            {
                                "key": "BAR",
                                "value": "Bar getting better"
                            },
                            {
                                "key": "FOO",
                                "value": "Foo is cool"
                            }
                        ]
                    }
                ]
            }
        }
    ]
}

容易进入这个吗?

{
    "BAR": "Bar getting better",
    "FOO": "Foo is cool"
}

【问题讨论】:

    标签: javascript json underscore.js lodash data-conversion


    【解决方案1】:

    在 Lodash 中,使用 _.keyBy,然后使用 _.mapValues

    var data = {"result":[{"content":{"resources":[{"prop":[{"key":"BAR","value":"Bar getting better"},{"key":"FOO","value":"Foo is cool"}]}]}}]},
        input = data.result[0].content.resources[0].prop;
    
    var result = _.mapValues(_.keyBy(input, 'key'), 'value');
    
    console.log(result);
    <script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>

    【讨论】:

    • 非常感谢,..也许还有一个问题:我怎样才能将它转换回大结构?
    • _.map(obj, function(v, k) { return { key: k, value: v }})
    • _.map(obj, (v, k) => ({key: k, value: v}))
    • 这并没有考虑到result.lengthresources.length都可能是> 1
    【解决方案2】:

    对于这个特定的数据结构,您可以使用reduce() 并返回对象。

    var data = {"result":[{"content":{"resources":[{"prop":[{"key":"BAR","value":"Bar getting better"},{"key":"FOO","value":"Foo is cool"}]}]}}]}
    
    var result = data.result[0].content.resources[0].prop.reduce(function(r, e) {
      r[e.key] = e.value;
      return r;
    }, {});
    
    console.log(result);

    ES6版本带箭头功能

    var data = {"result":[{"content":{"resources":[{"prop":[{"key":"BAR","value":"Bar getting better"},{"key":"FOO","value":"Foo is cool"}]}]}}]}
    var ar = data.result[0].content.resources[0].prop;
    
    var result = ar.reduce((r, e) => (r[e.key] = e.value, r), {});
    console.log(result);

    【讨论】:

    • 这是一个对象数组。
    • 你的箭头函数不需要return。只需使用(r, e) => (r[e.key] = e.value, r)
    【解决方案3】:

    这是一个使用原生 Javascript ES6 的解决方案,但有点复杂(我没有测试过):

    var data = ...
    var resultData = {}
    
    data.result.forEach(result => result.content.resources.forEach(resource => resource.prop.forEach(prop => resultData[prop.key] = prop.value)))
    

    或者,如果您只有一项顶级数组,那么试试 Javascript ES5

    var data = ...
    var resultData = {}
    
    data.result[0].content.resources[0].prop.forEach(function(prop) {
        resultData[prop.key] = prop.value
    });
    

    【讨论】:

      【解决方案4】:

      这里其他解决方案的问题是

      1. 他们选择data.result[0].content.resources[0].prop 处的数组,这没有考虑resultresources 数组的长度可能大于一个
      2. 嵌套的forEach 难以阅读和推理。

      为了解决这个问题,我创建了一个小型库deep-reduce,它可以帮助您减少/解开深层嵌套对象中的值。 deep-reduceArray.prototype.reduce 类似,但它在嵌套对象/数组中深入遍历。

      在你的数据上,你可以这样使用它

      // if path is ending in prop.number, 
      // then `item` is the object we want to untangle
      let untanglePropItems = (reduced, item, path) => {
        if (path.match(/prop\.\d+$/)) {
          reduced[item.key] = item.value
        }
        return reduced
      }
      
      // the reduced value is returned
      let reduced = deepReduce(deepNestedObject, untanglePropItems)
      

      Here is a demo in RunKit.

      【讨论】:

        猜你喜欢
        • 2017-11-22
        • 1970-01-01
        • 2022-11-29
        • 2021-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-20
        相关资源
        最近更新 更多