【问题标题】:Using array map to filter results with if conditional使用数组映射以 if 条件过滤结果
【发布时间】:2014-12-30 06:16:20
【问题描述】:

我正在尝试使用数组映射来进一步过滤对象,以准备将其发送到服务器以进行保存。我可以过滤到 1 个键值,这很棒,但我想更进一步,并根据内部的布尔值检查它们。

所以,现在这就是我所拥有的 -

$scope.appIds = $scope.applicationsHere.map( function(obj){
        if(obj.selected == true){
            return obj.id;
        }
    });

这对于提取 id 非常有用,但是如果他们选择的值 == false,我不想将它们推送到这个新数组中,所以我设置了一个条件来进一步过滤。这有点奏效,我得到了一个 id 数组,但是 .selected == false 的 id 仍然在数组中,只是值为 null。所以如果我在对象中有 4 个项目,其中 2 个是假的,它看起来像这样 -

 appIds = {id1, id2, null, null};

我的问题是 - 有没有办法在不放空值的情况下做到这一点。感谢阅读!

【问题讨论】:

  • 在 JS 中有 Array.prototype.filter 用于此目的的方法。

标签: javascript angularjs map


【解决方案1】:

您可以使用flatMap。过滤和映射合二为一。

$scope.appIds = $scope.applicationsHere.flatMap(obj => obj.selected ? obj.id : [])

【讨论】:

    【解决方案2】:

    如果有人在 2019 年遇到这个问题,这里有一些信息。

    我认为 reduce vs map + filter 可能在某种程度上取决于您需要循环的内容。对此不确定,但 reduce 似乎确实更慢。

    有一点是肯定的 - 如果您正在寻找性能改进,那么编写代码的方式非常重要!

    希望这对某人有所帮助

    【讨论】:

      【解决方案3】:

      您应该使用Array.prototype.reduce 来执行此操作。我确实做了一个little JS perf test 来验证这比.filter + .map 更有效。

      $scope.appIds = $scope.applicationsHere.reduce(function(ids, obj){
          if(obj.selected === true){
              ids.push(obj.id);
          }
          return ids;
      }, []);
      

      为了清楚起见,这里是我在 JSPerf 测试中使用的示例 .reduce

        var things = [
          {id: 1, selected: true},
          {id: 2, selected: true},
          {id: 3, selected: true},
          {id: 4, selected: true},
          {id: 5, selected: false},
          {id: 6, selected: true},
          {id: 7, selected: false},
          {id: 8, selected: true},
          {id: 9, selected: false},
          {id: 10, selected: true},
        ];
        
        	
      var ids = things.reduce((ids, thing) => {
        if (thing.selected) {
          ids.push(thing.id);
        }
        return ids;
      }, []);
      
      console.log(ids)

      编辑 1

      注意,截至 2/2018 Reduce + Push 在 Chrome 和 Edge 中最快,但在 Firefox 中比 Filter + Map

      【讨论】:

      • @DanMandel 可以在第一次推送时停止推送元素.. 我的意思是控制台上应该只打印一个值..?
      • @SivaprakashD 你的意思是你想找到第一个这样的例子吗?你可以var id = things.find(thing => thing.selected),它会在找到第一个实例developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 后停止。或者使用类似的.some 方法来获得一个真/假“这个对象是否存在于这个数组中”
      • @JustinL。感谢您的回复,我解决了这个表单另一个堆栈溢出问题....
      • @DanMandel - filter + map 怎么可能是 O(n^2) ?我认为是 O(2n),基本上是 O(n)
      • @DanMandel filter + map 绝对是 O(n) 而不是 n²。
      【解决方案4】:

      您正在寻找.filter() 函数:

        $scope.appIds = $scope.applicationsHere.filter(function(obj) {
          return obj.selected;
        });
      

      这将生成一个数组,其中仅包含“selected”属性为true(或truthy)的那些对象。

      edit 抱歉,我正在喝咖啡,我错过了 cmets - 是的,正如 jAndy 在评论中指出的那样,过滤然后只提取“id”值,它会是:

        $scope.appIds = $scope.applicationsHere.filter(function(obj) {
          return obj.selected;
        }).map(function(obj) { return obj.id; });
      

      一些函数库(比如Functional,在我看来并没有得到足够的喜爱)有一个.pluck() 函数来从对象列表中提取属性值,但是原生JavaScript 有一组非常精简的此类工具.

      【讨论】:

      • 然后我可以将 appids 变成一个只有 ids 而不是完整对象的 arra 吗?感谢您的帮助!
      • @user3201696 您需要在过滤器之后链接.map(),这绝对是可能的。
      • @jAndy 太棒了,谢谢!!在某个地方我可以看到一个例子,因为我确定如何将 2 链接在一起。返回后我会在这个过滤器内做地图吗?
      • @user3201696 看起来很像 .filter(function(obj) { return obj.selected; }).map(function(obj) { return obj.id1 }); 这将创建一个仅包含 id1 属性值的新数组。
      • @jAndy 哦,这正是我要找的,非常感谢!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-21
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      • 2020-03-17
      • 2020-11-23
      相关资源
      最近更新 更多