过滤和删除数组中的过滤元素
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_002
和tc_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
【讨论】:
以上是关于过滤和删除数组中的过滤元素的主要内容,如果未能解决你的问题,请参考以下文章