Wie entferne ich ein Element aus dem Array in der forEach-Schleife?

97

Ich versuche, ein Element in einem Array in einer forEachSchleife zu entfernen , habe jedoch Probleme mit den Standardlösungen, die ich gesehen habe.

Folgendes versuche ich gerade:

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

Ich weiß, dass es in die geht, ifweil ich YippeeeeeE!!!!!!!!!!!!!in der Konsole sehe .

MEIN PROBLEM: Ich weiß, dass meine for-Schleife und die Logik einwandfrei sind, aber mein Versuch, das aktuelle Element aus dem Array zu entfernen, schlägt fehl.

AKTUALISIEREN:

Versuchte die Antwort von Xotic750 und das Element wird immer noch nicht entfernt:

Hier ist die Funktion in meinem Code:

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

Hier ist die Ausgabe, bei der das Array noch nicht entfernt wird:

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

Es geht also offensichtlich wie angegeben in die if-Anweisung ein, aber es ist auch offensichtlich, dass das [• • •] noch vorhanden ist.

novicePrgrmr
quelle
7
Gibt es einen Grund, den Sie verwenden forEach? Wenn Sie Elemente entfernen möchten, ist die am besten geeignete Funktion filter.
Jon
2
Nicht, wenn Sie den Verweis auf das ursprüngliche Array beibehalten müssen.
Xotic750
Ja, wir möchten den Verweis auf das ursprüngliche Array beibehalten.
NovicePrgrmr
Aus Ihrer Frage geht nicht hervor, was das eigentliche Problem ist, das Sie haben. Können Sie ein Beispiel geben, vielleicht eine jsFiddle? Es scheint, dass Sie vielleicht das indexAttribut verwenden sollten, anstatt itemfür Ihresplice
Xotic750
@ Xotic750 Sorry, Klarstellung hinzugefügt.
NovicePrgrmr

Antworten:

234

Sieht so aus, als würden Sie das versuchen?

Iterieren und mutieren Sie ein Array mit 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>

Dies funktioniert gut für einfache Fälle, in denen Sie nicht zwei gleiche Werte wie benachbarte Array-Elemente haben. Andernfalls tritt dieses Problem auf.

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>

Was können wir also gegen dieses Problem tun, wenn wir ein Array iterieren und mutieren? Nun, die übliche Lösung ist, umgekehrt zu arbeiten. Verwenden Sie ES3 zwar, aber Sie können es auch für Zucker verwenden, wenn Sie dies bevorzugen

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, aber Sie wollten, dass Sie ES5-Iterationsmethoden verwenden. Nun und Option wäre die Verwendung von Array.prototype.filter, aber dies mutiert nicht das ursprüngliche Array, sondern erstellt ein neues. Obwohl Sie die richtige Antwort erhalten können, ist es nicht das, was Sie anscheinend angegeben haben.

Wir könnten auch ES5 Array.prototype.reduceRight verwenden , nicht wegen seiner reduzierenden Eigenschaft durch seine Iterationseigenschaft, dh umgekehrt iterieren.

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>

Oder wir könnten ES5 Array.protoype.indexOf so verwenden.

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>

Sie möchten jedoch speziell ES5 Array.prototype.forEach verwenden . Was können wir also tun? Nun, wir müssen Array.prototype.slice verwenden , um eine flache Kopie des Arrays und Array.prototype.reverse zu erstellen, damit wir umgekehrt arbeiten können, um das ursprüngliche Array zu mutieren.

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>

Schließlich bietet uns ES6 einige weitere Alternativen, bei denen wir keine flachen Kopien erstellen und diese umkehren müssen. Insbesondere können wir Generatoren und Iteratoren verwenden . Die Unterstützung ist derzeit jedoch relativ gering.

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>

In all dem ist etwas zu beachten, wenn Sie NaN gestrippt haben Vergleich mit Gleichheit nicht funktioniert aus dem Array entfernt haben, da dies in Javascript NaN === NaNfalsch ist. Aber wir werden das in den Lösungen ignorieren, da es sich um einen weiteren nicht näher bezeichneten Randfall handelt.

Da haben wir es also, eine vollständigere Antwort mit Lösungen, die noch Randfälle haben. Das allererste Codebeispiel ist immer noch korrekt, aber wie gesagt, es ist nicht ohne Probleme.

Xotic750
quelle
Danke für die Antwort. Ich habe versucht, Ihre Lösung zu verwenden, aber das Element wird immer noch nicht aus dem Array entfernt. Ich werde die Details in die Frage aufnehmen.
NovicePrgrmr
Setzen Sie console.log(review);nach dem forEach, wie in meinem Beispiel.
Xotic750
4
Vorsicht, dies bricht ab, wenn zwei aufeinanderfolgende Elemente gelöscht werden sollen: var review = ['a', 'a', 'c', 'b', 'a']; wird ['a', 'c', 'b'] ergeben
quentinadam
3
HINWEIS - Diese Antwort ist falsch! Die foreach durchlaufen das Array nach Index. Sobald Sie Elemente löschen, während Sie den Index der folgenden Elemente iterieren, ändert sich. In diesem Beispiel wird die Indexnummer 1 nach dem Löschen des ersten 'a' zu 'c'. Daher wird das erste 'b' nicht einmal ausgewertet. Da Sie nicht versucht haben, es zu löschen, war es einfach in Ordnung, aber das ist nicht der richtige Weg. Sie sollten eine umgekehrte Kopie des Arrays durchlaufen und dann Elemente im ursprünglichen Array löschen.
Danbars
4
@ Xotic750 - Die ursprüngliche Antwort (jetzt das erste Code-Snippet) ist falsch, einfach weil forEach nicht alle Elemente im Array durchläuft, wie ich im vorherigen Kommentar erklärt habe. Ich weiß, dass die Frage war, wie Elemente in einer forEach-Schleife entfernt werden können, aber die einfache Antwort ist, dass Sie das nicht tun. Da viele Leute diese Antworten lesen und oft blind Antworten kopieren (insbesondere akzeptierte Antworten), ist es wichtig, Fehler im Code zu beachten. Ich denke, dass die umgekehrte while-Schleife die einfachste, effizienteste und am besten lesbare Lösung ist und die akzeptierte Antwort sein sollte
danbars
37

Verwenden Sie Array.prototype.filteranstelle von 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);
Alemjerus
quelle
10

Obwohl die Antwort von Xotic750 mehrere gute Punkte und mögliche Lösungen bietet, ist manchmal einfach besser .

Sie wissen, dass das Array, auf dem iteriert wird, in der Iteration selbst mutiert wird (dh Entfernen eines Elements => Indexänderungen). Daher ist es am einfachsten, in einer altmodischen Sprache for(à la C ) rückwärts zu gehen :

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

Wenn Sie wirklich darüber nachdenken, forEachist a nur syntaktischer Zucker für eine forSchleife ... Wenn es Ihnen also nicht hilft, hören Sie bitte auf, sich den Kopf dagegen zu brechen.

CPHPython
quelle
1

Sie können dazu auch indexOf verwenden

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

Ich habe verstanden, dass Sie mithilfe einer Bedingung aus dem Array entfernen möchten und ein anderes Array haben möchten, dessen Elemente aus dem Array entfernt wurden. Ist richtig?

Wie wäre es damit?

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

Ich hoffe das hilft...

Übrigens habe ich 'for-loop' mit 'forEach' verglichen.

Wenn entfernen, falls eine Zeichenfolge 'f' enthält, ist das Ergebnis anders.

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"]
 */

Und entfernen Sie durch jede Iteration, auch ein Ergebnis ist anders.

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

Park Jun-Hong
quelle
0

Im Folgenden finden Sie alle Elemente, die nicht Ihren Sonderzeichen entsprechen!

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

So sollten Sie es machen:

review.forEach(function(p,index,object){
   if(review[index] === '\u2022 \u2022 \u2022'){
      console.log('YippeeeE!!!!!!!!!!!!!!!!')
      review.splice(index, 1);
   }
});
Alaeddin Hussein
quelle
1
Ich glaube nicht, dass dies der Fall ist. Ich habe meinen Code geändert, vorausgesetzt, p war ein Index, und jetzt kommt er nicht einmal mehr in die ifAnweisung.
NovicePrgrmr
3
@WhoCares Sie sollten die Spezifikation ecma-international.org/ecma-262/5.1/#sec-15.4.4.18 sehen. Die Argumente der callBack-Funktion sinditem, index, object
Xotic750
-1

Das Problem ist, dass beim Spleißen eines Arrays offensichtlich die Schlüssel oder Indizes der Werte geändert werden. Wenn Sie also die Nadel nacheinander auf "true" treffen, können Sie den nächsten Wert im Stapel übersehen.

Um dem entgegenzuwirken, können Sie Folgendes tun:

let review = ['a','a','a','b','c','a']

let tempArray = Array.from(review) 

let counter = 0

tempArray.forEach((item,index,obj)=>{
          if(item === 'a'){

            review.splice(index - counter, 1)
            counter++
           
           }

 }) 
 
 console.log(review)

Karl L.
quelle