过滤和删除数组中的过滤元素

Posted

技术标签:

【中文标题】过滤和删除数组中的过滤元素【英文标题】: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);

【问题讨论】:

What is the in-place alternative to Array.prototype.filter() 的可能重复项 可以使用下面的a.splice(0, 1); 【参考方案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

【讨论】:

以上是关于过滤和删除数组中的过滤元素的主要内容,如果未能解决你的问题,请参考以下文章

过滤阵列中的数组

php数组的重复值如何过滤掉

在 Python 中过滤数组中的 Anagram

过滤 php 中的数组,同时具有值​​和键相关条件

jQuery中的$.grep()方法的使用

如何比较 2 个数组中的值以过滤掉元素