简体   繁体   English

如何从 forEach 循环中的数组中删除元素?

[英]How to remove element from array in forEach loop?

I am trying to remove an element in an array in a forEach loop, but am having trouble with the standard solutions I've seen.我试图在forEach循环中删除数组中的一个元素,但我遇到了我见过的标准解决方案的问题。

This is what I'm currently trying:这是我目前正在尝试的:

review.forEach(function(p){
   if(p === '\u2022 \u2022 \u2022'){
      console.log('YippeeeE!!!!!!!!!!!!!!!!')
      review.splice(p, 1);
   }
});

I know it's getting into the if because I'm seeing YippeeeeeE!!!!!!!!!!!!!我知道它进入了if因为我看到了YippeeeeeE!!!!!!!!!!!!! in the console.在控制台中。

MY PROBLEM: I know that my for loop and if logic are sound, but my attempt to remove the current element from the array is failing.我的问题:我知道我的 for 循环和 if 逻辑是正确的,但是我试图从数组中删除当前元素的尝试失败了。

UPDATE:更新:

Tried out Xotic750's answer, and the element is still not being removed:尝试了 Xotic750 的答案,但该元素仍未被删除:

Here is the function in my code:这是我的代码中的 function:

review.forEach(function (item, index, object) {
    if (item === '\u2022 \u2022 \u2022') {
       console.log('YippeeeE!!!!!!!!!!!!!!!!')
       object.splice(index, 1);
    }
    console.log('[' + item + ']');
});

Here is the output where the array is still not removed:这是数组仍未删除的 output:

[Scott McNeil]
[reviewed 4 months ago]
[ Mitsubishi is AMAZING!!!]
YippeeeE!!!!!!!!!!!!!!!!
[• • •]

So obviously it is going into the if statement as directed, but it's also obvious that the [• • •] is still there.所以很明显它按照指示进入 if 语句,但也很明显 [• • •] 仍然存在。

It looks like you are trying to do this?看起来您正在尝试这样做?

Iterate and mutate an array using Array.prototype.splice使用Array.prototype.splice迭代和改变数组

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } var review = ['a', 'b', 'c', 'b', 'a']; review.forEach(function(item, index, object) { if (item === 'a') { object.splice(index, 1); } }); log(review);
 <pre id="out"></pre>

Which works fine for simple case where you do not have 2 of the same values as adjacent array items, other wise you have this problem.这适用于您没有 2 个与相邻数组项相同的值的简单情况,否则您会遇到此问题。

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } var review = ['a', 'a', 'b', 'c', 'b', 'a', 'a']; review.forEach(function(item, index, object) { if (item === 'a') { object.splice(index, 1); } }); log(review);
 <pre id="out"></pre>

So what can we do about this problem when iterating and mutating an array?那么在迭代和变异数组时,我们可以对这个问题做些什么呢? Well the usual solution is to work in reverse.那么通常的解决方案是反向工作。 Using ES3 while but you could use for sugar if preferred使用ES3 但你可以使用,如果首选糖

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } var review = ['a' ,'a', 'b', 'c', 'b', 'a', 'a'], index = review.length - 1; while (index >= 0) { if (review[index] === 'a') { review.splice(index, 1); } index -= 1; } log(review);
 <pre id="out"></pre>

Ok, but you wanted to use ES5 iteration methods.好的,但是您想使用 ES5 迭代方法。 Well and option would be to use Array.prototype.filter but this does not mutate the original array but creates a new one, so while you can get the correct answer it is not what you appear to have specified.好吧,选项是使用Array.prototype.filter但这不会改变原始数组而是创建一个新数组,因此虽然您可以获得正确答案,但它并不是您所指定的。

We could also use ES5 Array.prototype.reduceRight , not for its reducing property by rather its iteration property, ie iterate in reverse.我们也可以使用 ES5 Array.prototype.reduceRight ,不是因为它的减少属性而是它的迭代属性,即反向迭代。

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } var review = ['a', 'a', 'b', 'c', 'b', 'a', 'a']; review.reduceRight(function(acc, item, index, object) { if (item === 'a') { object.splice(index, 1); } }, []); log(review);
 <pre id="out"></pre>

Or we could use ES5 Array.protoype.indexOf like so.或者我们可以像这样使用 ES5 Array.protoype.indexOf

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } var review = ['a', 'a', 'b', 'c', 'b', 'a', 'a'], index = review.indexOf('a'); while (index !== -1) { review.splice(index, 1); index = review.indexOf('a'); } log(review);
 <pre id="out"></pre>

But you specifically want to use ES5 Array.prototype.forEach , so what can we do?但是你特别想使用 ES5 Array.prototype.forEach ,那我们怎么办? Well we need to use Array.prototype.slice to make a shallow copy of the array and Array.prototype.reverse so we can work in reverse to mutate the original array.那么我们需要使用Array.prototype.slice来制作数组的浅拷贝和Array.prototype.reverse以便我们可以反向工作以改变原始数组。

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } var review = ['a', 'a', 'b', 'c', 'b', 'a', 'a']; review.slice().reverse().forEach(function(item, index, object) { if (item === 'a') { review.splice(object.length - 1 - index, 1); } }); log(review);
 <pre id="out"></pre>

Finally ES6 offers us some further alternatives, where we do not need to make shallow copies and reverse them.最后,ES6 为我们提供了一些进一步的选择,我们不需要制作浅拷贝和反转它们。 Notably we can use Generators and Iterators .值得注意的是,我们可以使用Generators 和 Iterators However support is fairly low at present.然而,目前支持率相当低。

 var pre = document.getElementById('out'); function log(result) { pre.appendChild(document.createTextNode(result + '\\n')); } function* reverseKeys(arr) { var key = arr.length - 1; while (key >= 0) { yield key; key -= 1; } } var review = ['a', 'a', 'b', 'c', 'b', 'a', 'a']; for (var index of reverseKeys(review)) { if (review[index] === 'a') { review.splice(index, 1); } } log(review);
 <pre id="out"></pre>

Something to note in all of the above is that, if you were stripping NaN from the array then comparing with equals is not going to work because in Javascript NaN === NaN is false.以上所有内容需要注意的是,如果您从数组中剥离NaN ,那么与 equals 进行比较将不起作用,因为在 Javascript 中NaN === NaN是假的。 But we are going to ignore that in the solutions as it it yet another unspecified edge case.但是我们将在解决方案中忽略它,因为它是另一个未指定的边缘情况。

So there we have it, a more complete answer with solutions that still have edge cases.所以我们有了它,一个更完整的答案,解决方案仍然存在边缘情况。 The very first code example is still correct but as stated, it is not without issues.第一个代码示例仍然是正确的,但如前所述,它并非没有问题。

Use Array.prototype.filter instead of forEach :使用Array.prototype.filter而不是forEach

var pre = document.getElementById('out');

function log(result) {
  pre.appendChild(document.createTextNode(result + '\n'));
}

var review = ['a', 'b', 'c', 'b', 'a', 'e'];
review = review.filter(item => item !== 'a');
log(review);

Although Xotic750's answer provides several good points and possible solutions, sometimes simple is better .尽管Xotic750 的回答提供了几个优点和可能的解决方案,但有时简单更好

You know the array being iterated on is being mutated in the iteration itself (ie removing an item => index changes), thus the simplest logic is to go backwards in an old fashioned for (à la C language):您知道正在迭代的数组在迭代本身中发生了变化(即删除项目 => 索引更改),因此最简单的逻辑是在老式for (à la C语言)中倒退:

 let arr = ['a', 'a', 'b', 'c', 'b', 'a', 'a']; for (let i = arr.length - 1; i >= 0; i--) { if (arr[i] === 'a') { arr.splice(i, 1); } } document.body.append(arr.join());

If you really think about it, a forEach is just syntactic sugar for a for loop... So if it's not helping you, just please stop breaking your head against it.如果您真的考虑一下, forEach只是for循环的语法糖……所以如果它对您没有帮助,请停止反对它。

You could also use indexOf instead to do this您也可以使用 indexOf 来代替执行此操作

var i = review.indexOf('\u2022 \u2022 \u2022');
if (i !== -1) review.splice(i,1);

I understood that you want to remove from the array using a condition and have another array that has items removed from the array.我知道您想使用条件从数组中删除并拥有另一个从数组中删除项目的数组。 Is right?是对的?

How about this?这个怎么样?

 var review = ['a', 'b', 'c', 'ab', 'bc']; var filtered = []; for(var i=0; i < review.length;) { if(review[i].charAt(0) == 'a') { filtered.push(review.splice(i,1)[0]); }else{ i++; } } console.log("review", review); console.log("filtered", filtered);

Hope this help...希望这有助于...

By the way, I compared 'for-loop' to 'forEach'.顺便说一下,我将“for-loop”与“forEach”进行了比较。

If remove in case a string contains 'f', a result is different.如果在字符串包含 'f' 的情况下删除,则结果不同。

 var review = ["of", "concat", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "flatMap", "flatten", "forEach", "includes", "indexOf", "join", "keys", "lastIndexOf", "map", "pop", "push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toSource", "toString", "unshift", "values"]; var filtered = []; for(var i=0; i < review.length;) { if( review[i].includes('f')) { filtered.push(review.splice(i,1)[0]); }else { i++; } } console.log("review", review); console.log("filtered", filtered); /** * review [ "concat", "copyWithin", "entries", "every", "includes", "join", "keys", "map", "pop", "push", "reduce", "reduceRight", "reverse", "slice", "some", "sort", "splice", "toLocaleString", "toSource", "toString", "values"] */ console.log("========================================================"); review = ["of", "concat", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "flatMap", "flatten", "forEach", "includes", "indexOf", "join", "keys", "lastIndexOf", "map", "pop", "push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toSource", "toString", "unshift", "values"]; filtered = []; review.forEach(function(item,i, object) { if( item.includes('f')) { filtered.push(object.splice(i,1)[0]); } }); console.log("-----------------------------------------"); console.log("review", review); console.log("filtered", filtered); /** * review [ "concat", "copyWithin", "entries", "every", "filter", "findIndex", "flatten", "includes", "join", "keys", "map", "pop", "push", "reduce", "reduceRight", "reverse", "slice", "some", "sort", "splice", "toLocaleString", "toSource", "toString", "values"] */

And remove by each iteration, also a result is different.并且每次迭代删除,结果也不同。

 var review = ["of", "concat", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "flatMap", "flatten", "forEach", "includes", "indexOf", "join", "keys", "lastIndexOf", "map", "pop", "push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toSource", "toString", "unshift", "values"]; var filtered = []; for(var i=0; i < review.length;) { filtered.push(review.splice(i,1)[0]); } console.log("review", review); console.log("filtered", filtered); console.log("========================================================"); review = ["of", "concat", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "flatMap", "flatten", "forEach", "includes", "indexOf", "join", "keys", "lastIndexOf", "map", "pop", "push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toSource", "toString", "unshift", "values"]; filtered = []; review.forEach(function(item,i, object) { filtered.push(object.splice(i,1)[0]); }); console.log("-----------------------------------------"); console.log("review", review); console.log("filtered", filtered);

Here is how you should do it:以下是您应该如何操作:

review.forEach(function(p,index,object){
   if(review[index] === '\u2022 \u2022 \u2022'){
      console.log('YippeeeE!!!!!!!!!!!!!!!!')
      review.splice(index, 1);
   }
});

The following will give you all the elements which is not equal to your special characters!以下将为您提供所有不等于您的特殊字符的元素!

review = jQuery.grep( review, function ( value ) {
    return ( value !== '\u2022 \u2022 \u2022' );
} );

I had problems with the following code.我在使用以下代码时遇到问题。 My solution follows after.我的解决方案如下。 First, the problem: Let's assume you want to trim strings, and discard the string with a 'c' in it:首先是问题:假设您要修剪字符串,并丢弃其中带有“c”的字符串:

 var review = [' a ', ' b ', ' c ', ' d ', ' e ']; review.forEach(function(item, index) { review[index] = item.trim(); console.log("After trimming, the item is ", review[index]); if (review[index] === 'c') { review.splice(index, 1); } }); console.log("Review is now: "); console.log(review);

If you run the above piece of code, you will see that ' d ' is never trimmed.如果你运行上面的代码,你会看到 'd' 永远不会被修剪。 It remains in the review array, with spaces before and after it.它保留在评论数组中,前后都有空格。

在此处输入图像描述

That's because you are messing with the review array that the foreach is built on.那是因为你弄乱了构建 foreach 的审查数组。 It's a lot better to make a copy of the array, and push elements into it that are OK to keep, and skip the ones that are not.最好复制数组,然后将可以保留的元素推入其中,并跳过不保留的元素。 Then, output the new FinalArray, like this:然后,output 新的 FinalArray,如下所示:

 var review = [' a ', ' b ', ' c ', ' d ', ' e ']; var finalArray = []; review.forEach(function(item, index) { // Add it to the new array first. If it turns out to be bad, remove it before going onto // the next iteration. finalArray.push(item.trim()); console.log("After trimming, the item is ", item.trim()); if (item.trim() == 'c') { // skip c finalArray.pop(); // This way, removing it doesn't affect the original array. } }); console.log("FinalArray is now: "); console.log(finalArray);

As you can see, this worked perfectly:如您所见,这非常有效:

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM