【问题标题】:How to combine _.map and _.filter in a more efficient way?如何以更有效的方式结合 _.map 和 _.filter?
【发布时间】:2017-05-30 07:07:21
【问题描述】:

我在我的 Angular 项目中使用 Lodash,我想知道是否有更好的方法来编写以下代码:

$scope.new_arr = _.map(arr1, function(item){
    return _.assign(item, {new_id: _.find(arr2, {id: item.id})});
  });
$scope.new_arr = _.filter($scope.new_arr, function (item) {
  return item.new_id !== undefined;
});

我正在尝试将一个数组中的值组合到另一个数组中的相同对象,并且我想忽略两个数组中都没有出现的对象(它类似于 sql 语言中的联接或左外联接)。

这里有一个代码示例:Click me!

【问题讨论】:

    标签: javascript angularjs lodash


    【解决方案1】:

    这里提供的答案都是 O(n^2) 的运行时间,因为它们首先在第一个数组上运行一个外循环,在第二个数组上运行一个内循环。您可以改为在 O(n) 中运行它。首先,在一个循环中创建 arr2 中所有 id 的 hashmap;这将允许我们进行订单 1 查找。在 arr1 的第二个循环中,检查这个 hashmap 以确定这些项目是否存在 O(n)。总复杂度为 n + n = 2n,即 O(n)。

    // provision some test arrays
    var arr1 = [
        {
            id: 2
        },
        {
            id: 4
        },
        {
            id: 6
        }
    ]
    
    var arr2 = [
        {
            id: 3
        },
        {
            id: 4
        },
        {
            id: 5
        },
        {
            id: 6
        }
    ]
    
    // First, we create a map of the ids of arr2 with the items. Complexity: O(n)
    var mapIdsToArr2Items = _.reduce(arr2, function(accumulator, item) {
        accumulator[item.id] = item;
        return accumulator;
    }, {});
    
    // Next, we use reduce (instead of a _.map followed by a _.filter for slightly more performance.
    // This is because with reduce, we loop once, whereas with map and filter, 
    // we loop twice). Complexity: O(n)
    var combinedArr = _.reduce(arr1, function(accumulator, item) {
    
        // Complexity: O(1)
        if (mapIdsToArr2Items[item.id]) {
            // There's a match/intersection! Arr1's item matches an item in arr 2. Include it
            accumulator.push(item);
        }
        return accumulator;    
    }, []);
    
    console.log(combinedArr)
    

    【讨论】:

      【解决方案2】:

      我认为最好使用链接

      $scope.new_arr = _.chain(arr1)
          .map(function(item) {
              return _.merge(
                  {}, // to avoid mutations
                  item, 
                  {new_id: _.find(arr2, {id: item.id})}
              ); 
          })
          .filter('new_id')
          .value();
      

      【讨论】:

      • +1 表示结果符合预期。从未使用过链并与 Lodash 合并,你能解释一下这里发生了什么,或者至少链是如何工作的吗?谢谢..
      • @ValiD about merge lodash.com/docs/4.17.4#merge,链接的常见想法是将上一步(函数)的结果传递到下一步以减少代码等,但链接@ 987654322@选择你的命运)
      • 如果使用 Lodash,这个是最好的答案。
      【解决方案3】:

      https://jsfiddle.net/3xjdqsjs/6/

      试试这个:

        $scope.getItemById = (array, id) => {
          return array.find(item => item.id == id);
        };
      
        $scope.mergeArrays = () => {
         let items_with_ids = arr1.filter(item => !_.isNil($scope.getItemById(arr2,item.id)));
         return items_with_ids.map(item => _.assign(item, {new_id: $scope.getItemById(arr2,item.id)}));
        };
      

      【讨论】:

      • 成功了!我注意到您使用了诸如 find 和 map 之类的数组函数,而不是 lodash 函数。这样效率更高吗?
      【解决方案4】:

      你可以先用arr1创建一个Map,然后用arr1的属性映射arr2的项目。

      var arr1 = [{ id: 1, title: 'z' }, { id: 2, title: 'y' }, { id: 3, title: 'x' }, { id: 4, title: 'w' }, { id: 5, title: 'v' }],
          arr2 = [{ id: 2, name: 'b' }, { id: 3, name: 'c' }, { id: 4, name: 'd' }, { id: 5, name: 'e' }],
          map = new Map(arr1.map(a => [a.id, a])),
          result = arr2.map(a => Object.assign({}, a, map.get(a.id)));
      
      console.log(result);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

      • 很好.. 没有考虑设置选项.. 在您的解决方案中,我缺少“名称”字段。我想将具有相同 id 的对象添加到另一个字段下的“new_arr”中。我知道这看起来像是字段的乘法,但这只是我真正需要的一个例子
      猜你喜欢
      • 2016-05-17
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 2014-11-04
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多