【问题标题】:Lodash keyBy for multiple nested level arraysLodash keyBy 用于多个嵌套级别数组
【发布时间】:2016-12-02 17:35:59
【问题描述】:

我有一个对象数组,我想将其转换为以id 为键的键值对映射。但是,我想在根级别和recipes 属性中都这样做。

数组resp

[
  {
    "id": "1",
    "recipes": [
      {
        "id": 4036
      },
      {
        "id": 4041
      }
    ]
  },
  {
    "id": "2",
    "recipes": [
      {
        "id": 4052
      },
      {
        "id": 4053
      }
    ]
  }
]

我遇到了_.keyBy(),它将一个属性映射为键,但它不允许嵌套级别。

功能:

var respObj = _.keyBy(resp, 'id');

是否有一个优雅的解决方案来按摩resp 以使嵌套在数组中的所有对象都使用id 作为键?

谢谢!

【问题讨论】:

    标签: javascript arrays object lodash


    【解决方案1】:

    您可以使用_.keyBy_.mapValues 来实现

    _.chain(resp)
        .keyBy('id')
        .mapValues(function(item) {
            item.recipes = _.keyBy(item.recipes, 'id');
            return item;
        })
        .value();
    

    【讨论】:

    • 非常适合我的用例的解决方案!谢谢!
    【解决方案2】:

    这是一个通用的解决方案,在数组上递归运行 _.keyBy,以及其中的对象:

    function deepKeyBy(arr, key) {
      return _(arr)
        .map(function(o) { // map each object in the array
          return _.mapValues(o, function(v) { // map the properties of the object
            return _.isArray(v) ? deepKeyBy(v, key) : v; // if the property value is an array, run deepKeyBy() on it
          });
        })
        .keyBy(key); // index the object by the key
    }
    

    我在示例中添加了另一个级别的数据(成分):

    function deepKeyBy(arr, key) {
      return _(arr)
        .map(function(o) {
          return _.mapValues(o, function(v) {
            return _.isArray(v) ? deepKeyBy(v, key) : v;
          });
        })
        .keyBy(key);
    }
    
    var arr = [{
      "id": "1",
      "recipes": [{
        "id": 4036,
        "ingerdients": [{
          "id": 5555555
        }, {
          "id": 5555556
        }, {
          "id": 5555557
        }]
      }, {
        "id": 4041
      }]
    }, {
      "id": "2",
      "recipes": [{
        "id": 4052
      }, {
        "id": 4053
      }]
    }];
    
    var result = deepKeyBy(arr, 'id');
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

    【讨论】:

    • 这太棒了。应该考虑使用递归解决方案:)
    【解决方案3】:

    您可以获得一个扁平化的食谱集合,连接响应,然后按 id 键:

    var result = _.chain(resp)
        .flatMap('recipes')
        .concat(resp)
        .keyBy('id')
        .value()
    

    flatMap 调用将从响应中提取所有配方并将数组展平,因此我们只剩下以下内容:

    [
        { "id": 4036 },
        { "id": 4041 },
        { "id": 4052 },
        { "id": 4053 }
    ]
    

    然后使用concat 将响应附加到此数组,因此我们有:

    [
        { "id": 4036 },
        { "id": 4041 },
        { "id": 4052 },
        { "id": 4053 },
        { "id": "1", recipes: ... }, 
        { "id": "2", recipes: ... } 
    ]
    

    最后我们使用keyBy得到所需的结构。

    		var resp = [
    		  {
    		    "id": "1",
    		    "recipes": [
    		      {
    		        "id": 4036
    		      },
    		      {
    		        "id": 4041
    		      }
    		    ]
    		  },
    		  {
    		    "id": "2",
    		    "recipes": [
    		      {
    		        "id": 4052
    		      },
    		      {
    		        "id": 4053
    		      }
    		    ]
    		  }
    		]
    
    	var result = _.chain(resp)
    		.flatMap('recipes')
    		.concat(resp)
    		.keyBy('id')
    		.value()
    
    document.getElementById('result').textContent = JSON.stringify(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
    
    <p>
      <pre id="result"></pre>
    </p>

    【讨论】:

    • 有趣.. flatMap() 和 concat() 如何将配方放回父对象?
    • 添加说明。
    猜你喜欢
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 2019-02-14
    • 1970-01-01
    • 2020-11-04
    相关资源
    最近更新 更多