【问题标题】:Filter and delete filtered elements in an array过滤和删除数组中的过滤元素
【发布时间】:2016-09-19 23:57:13
【问题描述】:

我想删除原始数组(即var a)中的特定元素。我filter() 那个数组和splice() 返回了新数组。但这不会影响此代码中的原始数组。如何轻松地从原始数组中删除这些元素?

var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}]

var b = a.filter(function (e) {
    return e.name === 'tc_001';
});

b.splice(0,1);

console.log(a);
console.log(b);

【问题讨论】:

标签: javascript arrays node.js


【解决方案1】:

Array.prototype.filter() 方法用于收集一个元素集,而不仅仅是一项。如果您想通过评估一个条件来获得一个项目,那么您还有其他三个选项:

  • Array.prototype.indexOf()
  • Array.prototype.findIndex()
  • Array.prototype.find()

因此,只有当您想对多个项目进行操作时,您才应该考虑使用过滤器功能。就需要完成的工作而言,没有一个答案是完整的。

他们使用过滤器功能来隔离一个集合(在这个例子中只是一个项目),但他们没有展示如何摆脱整个集合。好吧,让我们澄清一下。

如果您只想查找并删除数组中的一项,则应这样做

var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}];
a.splice(a.findIndex(e => e.name === "tc_001"),1);
console.log(a);

但是,既然您提到“特定元素”是复数形式,那么您将需要收集一组选定的项目,并对集合中的每个元素逐个执行上述工作。所以正确的方法是。

var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}],
    b = a.filter(e => e.name === "tc_001");
b.forEach(f => a.splice(a.findIndex(e => e.name === f.name),1));
console.log(a);

无论您选择的列表中有多少元素,这都可以完成您的工作。然而我相信虽然这看起来合乎逻辑,但它确实做了很多多余的工作。首先过滤器,然后每个过滤的元素都会索引搜索这个和那个。尽管我知道 findIndex 非常快,但我希望这个结果会明显变慢,尤其是对于大型数组。让我们找到一个 O(n) 的解决方案。给你:

var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}];
a = a.reduce((p,c) => (c.name !== "tc_001" && p.push(c),p),[]);
console.log(a);

所以一定是这个。

【讨论】:

  • 我没有得到最后一个。您能否将最后一个分解为更简单的形式 a.reduce(function (pre, curr) { ` if (curr.name !=="tc_001"){` ` return p.push(curr);` ` }else{` ` return p,[] ;` ` }` }) 为什么要将当前对象推到前一个对象?
  • 是的,我们没有修改原始数组,而是创建了一个新数组,但最后我们用 reduce 函数的结果覆盖了原始数组。关于你接近的代码......它应该看起来像这样 a.reduce(function (pre, curr) { if (curr.name !=="tc_001") p.push(curr); return p;}, []) 我们不能返回 p.push(curr) 的结果,因为 push() 函数不会返回推送的数组作为结果,而是返回长度它。这很愚蠢。所以我们必须单独返回 p 数组才能使 reduce 函数工作。在我的代码中,这就是为什么 ,p 出现在最后。
  • 为什么我们需要一个空数组来传递给reduce方法?
  • @Srinesh 它是初始化参数。因为 p 以一个空数组开头,并且每次都被填充。
【解决方案2】:

另一种方法是在两个列表中过滤,如下所示:

const originalList = [{condition:true}, {condition: false}, {condition: true}];

// wished lists
const listWithTrue = originalList.filter(x=>x.condition);
const listWithFalse = originalList.filter(x=>!x.condition); // inverse condition

【讨论】:

  • 我认为这个解决方案更加优雅和简单。
  • 是的,但是它会创建一个新数组,所以如果需要通过引用更改当前数组,请使用其他解决方案。
  • @judian 通常最好注意改变原始数组。除非您担心性能,否则这是一个很好的解决方案。
【解决方案3】:

如果我理解你的话,你想从原始数组 (a) 中删除与过滤器匹配的元素,但将它们保留在新数组中 (b) 看看这个解决方案是否是你需要的:

var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}]

var b = a.filter(function (e) {
      return e.name === 'tc_002'
});

b.forEach(function(element) {
   console.log(element)
   var index = a.indexOf(element)
   console.log(index)
   a.splice(index, 1)
})

结果:

a = [{"name":"tc_001"},{"name":"tc_003"}] b = [{"name":"tc_002"}]

【讨论】:

    【解决方案4】:

    var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_002'}, {name:'tc_002'}, {name:'tc_003'}];
    
    while ( a.findIndex(e => e.name === 'tc_002' ) >= 0 )
     a.splice( a.findIndex(f => f.name === 'tc_002'),1);
     
    console.log(a);

    【讨论】:

      【解决方案5】:

      您可以将过滤器数组分配给自身,然后对其应用拼接。

      下面的例子:

      var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}]
      a = a.filter(function (e) {
          return e.name === 'tc_001';
      });
      
      a.splice(0,1);
      

      【讨论】:

      • 这与 AlexD 所做的有什么不同?
      【解决方案6】:

      您可以对原始数组进行更改:

      var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}]
      a = a.filter(function (e) {
          return e.name === 'tc_001';
      });
      a.splice(0,1);
      

      或者在您自己的代码中,只需将您对b所做的一切都应用到a

      a = b
      

      如果我详细说明每个动作的作用,也许会更清楚。

      var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}]
      // You now have array a with 3 elements.
      
      b = a.filter(function (e) {
          return e.name === 'tc_001';
      });
      // a is still 3 elements, b has one element (tc_001)
      
      b.splice(0,1);
      // You remove the first element from b, so b is now empty.
      

      如果您想从a 中删除元素tc_002tc_003 但将它们保留在b 中,您可以这样做:

      var a = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_003'}]
      b = a.filter(function (e) {
          return e.name != 'tc_001';
      });
      a = a.filter(function(item) { return b.indexOf(item) == -1; });
      console.log(a); // tc_001
      console.log(b); // tc_002, tc_003
      

      【讨论】:

      • 那么在更改a {name:'tc_002'}, {name:'tc_003'}的引用后我将如何使用这两个元素
      • 您在问题中没有提及任何相关内容。您想从 a 中删除元素,但将它们保存在单独的数组中?
      • 问:“我怎样才能轻松地删除原始数组的那些元素?”
      • 答案就是我写的,但你现在提到了“之后使用这两个元素”。如果你能澄清你需要什么,我相信我能提供帮助。
      【解决方案7】:

      你可以试试这个方法。

      向后循环数组,在每次迭代时进行比较,如果匹配则删除。

      在此示例中,目标是删除名称为“tc_001”的那些数组

      var x = [{name:'tc_001'}, {name:'tc_002'}, {name:'tc_001'}, {name:'tc_003'}, {name:'tc_001'},{name:'tc_002'}, {name:'tc_001'}, {name:'tc_003'}, {name:'tc_001'}]
      
      var find_and_delete = "tc_0001"
      
      for (var i = x.length - 1; i >= 0; i--) {
          if(x[i].name == find_and_delete){     
           x.splice(i,1)
          }
      }
      

      在这之后 x 的新值是

      [{name:'tc_002'}, {name:'tc_003'}, {name:'tc_002'}, {name:'tc_003'}]
      

      【讨论】:

        【解决方案8】:

        如果能够过滤多个元素很重要,那么使用reduce 遍历数组并将它们分类为过滤和未过滤的类别怎么样。这样做的好处是在处理结果之前不会对数组进行多次迭代。

        function splitArray (arr, filterFn) {
        
          return arr.reduce((acc, el) => {
        
            const conditionMet = filterFn(el)
        
            if (conditionMet)
              return { ...acc, filtered: [...acc.filtered, el] }
        
            return { ...acc, unfiltered: [...acc.unfiltered, el] }
        
          }, { filtered: [], unfiltered: [] })
        }
        

        然后您可以将一个数组拆分为两个派别,并将第二个派系应用于原始数组:

        const arr = [1, 2, 3, 4]
        
        const {filtered, unfiltered} = splitArray(arr, el => el > 2)
        
        console.log(filtered)   // [1, 2]
        console.log(unfiltered) // [3, 4]
        
        /* Do something with filtered */
        
        arr = unfiltered
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-01-05
          • 1970-01-01
          • 1970-01-01
          • 2020-09-12
          • 2022-11-03
          • 1970-01-01
          • 2017-01-04
          • 1970-01-01
          相关资源
          最近更新 更多