【问题标题】:Lodash - Find deep in array of objectLodash - 在对象数组中查找深处
【发布时间】:2017-01-12 10:37:41
【问题描述】:

我有一个这样的对象数组

[
    {
        'a': 10,
        elements: [
            {
                'prop': 'foo',
                'val': 10
            },
            {
                'prop': 'bar',
                'val': 25
            },
            {
                'prop': 'test',
                'val': 51
            }
        ]
    },
    {
        'b': 50,
        elements: [
            {
                'prop': 'foo',
                'val': 30
            },
            {
                'prop': 'bar',
                'val': 15
            },
            {
                'prop': 'test',
                'val': 60
            }
        ]
    },
]

propfoo 时,我需要对属性Val 求和。 因此,我必须搜索元素并获取propfoo 的所有对象。有了这些对象,我应该总结 val 属性。

我尝试使用_.find_.pick 等的多种组合,但我没有得到正确的结果。有人可以帮我吗?

【问题讨论】:

    标签: javascript lodash


    【解决方案1】:

    这是一个解决方案,先flattens 元素,然后filters 得到summing val 属性之前所需的元素:

    var result = _.chain(data)
        .map('elements')               // pluck all elements from data
        .flatten()                     // flatten the elements into a single array
        .filter({prop: 'foo'})         // exatract elements with a prop of 'foo'
        .sumBy('val')                  // sum all the val properties
        .value()
    

    链接是一种在返回值之前对某些数据应用一系列操作的方法。上面的示例使用显式链接,但可以(也许应该)使用隐式链接编写:

    var result = _(data)
        .map('elements')
        .flatten()
        .filter({prop: 'foo'})
        .sumBy('val');
    

    【讨论】:

    • 似乎是完美的解决方案,但为了更好地理解该解决方案的未来使用,请在每个方法后解释结果。
    【解决方案2】:

    这里有一个解决这个问题的方法:

    const _ = require('lodash')
    
    let deepFind = (JSONArray, keyPath, keyValue) => _.find(JSONArray, _.matchesProperty(keyPath, keyValue))
    
    let JSONArray = [{a:1, b:2, c:{d: "cd"}}, {a:3, b:4, c:{d: "ef"}}, {a:3, b:4, c:[{d: "ef"}]} ]
    
    console.log(deepFind(JSONArray, "c.d", "cd"))
    // {a:1, b:2, c:{d: "cd"}}
    
    console.log(deepFind(JSONArray, "b", 4)) 
    //{a:3, b:4, c:{d: "ef"}}
    
    console.log(deepFind(JSONArray, ['c', 'd'], "cd"))
    //{a:1, b:2, c:{d: "cd"}}
    
    console.log(deepFind(JSONArray, 'c[0].d' /* OR ['c', '0', 'd']*/, "ef"))
    //{a:1, b:2, c:{d: "cd"}}

    【讨论】:

      【解决方案3】:

      我创建了您可以使用的库:https://github.com/dominik791/obj-traverse

      findAll() 方法应该可以解决您的问题。第一个参数是根对象,不是数组,所以你应该先创建它:

      var rootObj = {
        name: 'rootObject',
        elements: [
          {
            'a': 10,
             elements: [ ... ]
          },
          {
             'b': 50,
             elements: [ ... ]
          }
        ]
      };
      

      然后使用findAll()方法:

      var matchingObjects = findAll( rootObj, 'elements', { 'prop': 'foo' } );
      

      matchingObjects 变量存储所有prop 等于foo 的对象。最后计算你的总和:

      var sum = 0;
      matchingObjects.forEach(function(obj) {
        sum += obj.val;
      });
      

      【讨论】:

        【解决方案4】:

        披露:我是那个库的作者


        您可以使用 deepdash 中的_.eachDeep 方法:

        let sum = 0;
        _.eachDeep(obj, (value, key, parent) => {
          sum += (key == 'prop' && value == 'foo' && parent.val) || 0;
        });
        

        这是您的情况的example

        【讨论】:

        • 这个库有很大的潜力,但文档却很少。
        • 谢谢。您能否提供更详细的反馈文档有什么问题,欢迎在 GitHub 上提出问题。
        • 只需为每个函数提供 2 个示例(尽可能简单,以及一个中间示例)。但是有一个尽可能简单的例子是绝对必要的。
        【解决方案5】:

        你可以遍历数据并得到总和。试试这个:

        var arr=[
             {
                 'a': 10,
                 elements: [
                     {
                         'prop': 'foo',
                         'val': 10
                     },
                     {
                         'prop': 'bar',
                         'val': 25
                     },
                     {
                         'prop': 'test',
                         'val': 51
                     }
                 ]
             },
             {
                 'b': 50,
                 elements: [
                     {
                         'prop': 'foo',
                         'val': 30
                     },
                     {
                         'prop': 'bar',
                         'val': 15
                     },
                     {
                         'prop': 'test',
                         'val': 60
                     }
                 ]
             }
         ];
         var sum=0;
         for(x in arr){
         for(i in arr[x]['elements']){
           if(arr[x]['elements'][i]['prop'] == 'foo'){
        	   sum=sum+arr[x]['elements'][i]['val'];
           }
         }
        
         }
        
         console.log(sum);

        使用过滤器:

        var arr=[
             {
                 'a': 10,
                 elements: [
                     {
                         'prop': 'foo',
                         'val': 10
                     },
                     {
                         'prop': 'bar',
                         'val': 25
                     },
                     {
                         'prop': 'test',
                         'val': 51
                     }
                 ]
             },
             {
                 'b': 50,
                 elements: [
                     {
                         'prop': 'foo',
                         'val': 30
                     },
                     {
                         'prop': 'bar',
                         'val': 15
                     },
                     {
                         'prop': 'test',
                         'val': 60
                     }
                 ]
             }
         ];
         var sum=0;
        
        arr.filter(function (person) { 
          person['elements'].filter(function(data){
          if (data.prop == "foo"){
            sum=sum+data.val;
          }
          });
          });
                   
                   console.log(sum);

        【讨论】:

          【解决方案6】:

          如果有人需要,这里是对我有用的解决方案。但我的情况有点不同,我需要找到一个与 id 匹配的数组。

          这里有一个流函数,它不是真的需要,但它确实使代码更容易阅读

          const flow = functions => data =>
              functions.reduce((value, func) => func(value), data);
          
             const arr = [
                  {
                      'a': 10,
                      elements: [
                          {
                              'prop': 'foo',
                              'val': 10
                          },
                          {
                              'prop': 'bar',
                              'val': 25
                          },
                          {
                              'prop': 'test',
                              'val': 51
                          }
                      ]
                  },
                  {
                      'b': 50,
                      elements: [
                          {
                              'prop': 'foo',
                              'val': 30
                          },
                          {
                              'prop': 'bar',
                              'val': 15
                          },
                          {
                              'prop': 'test',
                              'val': 60
                          }
                      ]
                  },
              ]
          
              const result= _.flow([
                  data => _.map(data, 'elements'), // get all elements from the array 
                  data => _.flatten(data), // create a singler array 
                  data => _.find(data, { val: 65 }) // find the needed value in array 
                  // you can keep on adding logic here depending on your need
              ])(arr); // the inital array 
              
          

          如果您不想使用流功能,我认为也可以这样做 我没有测试代码,但它应该可以工作

          const results = _.find(_.flatten(_.map(arr, 'elements')), { val: 65 });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-21
            • 2016-08-10
            • 2017-03-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多