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


97

我正在尝试删除一个数组中的元素 forEach循环中,但遇到的标准解决方案遇到了麻烦。

这是我目前正在尝试的方法:

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

我知道它正在进入,if因为我YippeeeeeE!!!!!!!!!!!!!在控制台中看到了。

我的问题:我知道我的for循环和if逻辑是正确的,但是我尝试从数组中删除当前元素失败。

更新:

尝试了Xotic750的答案,但该元素仍未被删除:

这是我的代码中的函数:

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

以下是仍未删除数组的输出:

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

因此,很明显,它已按照指示进入if语句,但很显然[•••]仍然存在。


8
您有使用理由forEach吗?如果要删除项目,最合适的功能是filter
2014年

2
如果您需要保留对原始数组的引用,则不需要。
Xotic750

是的,我们希望保留对原始数组的引用。
novicePrgrmr 2014年

从您的问题尚不清楚,您遇到的实际问题是什么?您能举个例子,也许是jsFiddle吗?看来你也许应该使用index属性,而不是item为你splice
Xotic750

@ Xotic750抱歉,添加了说明。
novicePrgrmr 2014年

Answers:


235

看来您正在尝试这样做?

使用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>

在没有与相邻数组项具有相同值的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>

那么,当迭代和变异数组时,我们该如何处理呢?好吧,通常的解决方案是反向工作。使用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>

好的,但是您想使用ES5迭代方法。好吧,选择是使用Array.prototype.filter,但这不会改变原始数组,而是创建一个新数组,因此尽管您可以获得正确的答案,但它似乎并不是您指定的。

我们也可以使用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>

或者我们可以像这样使用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>

但是您特别想使用ES5 Array.prototype.forEach,那么我们该怎么办?那么我们需要使用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>

最后,ES6为我们提供了其他一些选择,而无需制作浅表副本并将其反转。值得注意的是,我们可以使用Generators和Iterators。但是目前支持还很低。

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>

在上述所有内容中要注意的一点是,如果要从数组中删除NaN,则与equals的比较将无法工作,因为在Javascript中NaN === NaN为false。但是我们将在解决方案中忽略它,因为这是另一个未指定的边缘情况。

因此,有了解决方案,仍然可以解决边缘问题。第一个代码示例仍然是正确的,但是如上所述,它并非没有问题。


谢谢回答。我尝试使用您的解决方案,但它仍然没有从数组中删除该元素。我将在问题中提出细节。
novicePrgrmr 2014年

放在console.log(review);后面forEach,如我的示例所示。
Xotic750 2014年

4
小心,如果要删除两个连续的元素,这会中断:var review = ['a','a','c','b','a']; 将产生['a','c','b']
quentinadam

3
注意-这个答案是错误的!foreach通过索引遍历数组。一旦在迭代以下项目时删除元素,索引就会更改。在此示例中,删除第一个“ a”后,索引号1现在变为“ c”。因此,甚至不会评估第一个“ b”。由于您没有尝试删除它,所以碰巧就可以了,但是那不是办法。您应该遍历数组的反向副本,然后删除原始数组中的项目。
danbars

4
@ Xotic750-原始答案(现在是第一个代码段)是错误的,仅因为forEach不会循环遍历数组中的所有元素,正如我在上一条评论中所解释的那样。我知道问题是如何删除forEach循环中的元素,但简单的答案是您不这样做。由于许多人正在阅读这些答案,并且多次盲目地复制答案(尤其是被接受的答案),因此重要的是要注意代码中的缺陷。我认为反向while循环是最简单,最有效和最易读的解决方案,应该是公认的答案
danbars

37

使用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);

10

尽管Xotic750的答案提供了一些优点和可能的解决方案,但有时简单会更好

您知道要迭代的数组在迭代本身中就已经发生了变异(即,删除项=>索引更改),因此最简单的逻辑就是以旧式forC语言)倒退:

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());

如果您真的考虑过,a forEach只是一个for循环的语法糖...因此,如果它对您没有帮助,请不要再为此大伤脑筋。


1

您也可以使用indexOf代替

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

1

我了解您想使用条件从数组中删除,并让另一个数组具有从数组中删除的项目。是正确的?

这个怎么样?

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);

希望这个帮助...

顺便说一下,我将“ for-loop”与“ forEach”进行了比较。

如果在字符串包含“ 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"]
 */

并且由每次迭代删除,结果也是不同的。

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);


0

以下内容将为您提供不等于您的特殊字符的所有元素!

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.