ForEach döngüsünde diziden eleman nasıl kaldırılır?


103

forEachDöngüdeki bir dizideki bir öğeyi kaldırmaya çalışıyorum , ancak gördüğüm standart çözümlerle ilgili sorun yaşıyorum.

Şu anda denediğim şey bu:

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

İçine girdiğini biliyorum ifçünkü YippeeeeeE!!!!!!!!!!!!!konsolda görüyorum .

SORUNUM: For döngümün ve mantığımın sağlam olduğunu biliyorum, ancak mevcut öğeyi diziden kaldırma girişimim başarısız oluyor.

GÜNCELLEME:

Xotic750'nin cevabını denedim ve öğe hala kaldırılmıyor:

Kodumdaki işlev şu şekildedir:

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

Dizinin hala kaldırılmadığı çıktı:

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

Yani açıkça belirtildiği gibi if ifadesine giriyor, ama aynı zamanda [• • •] 'nin hala orada olduğu da açıktır.


8
Kullanmanızın bir nedeni var mı forEach? Öğeleri kaldırmak istiyorsanız, en uygun işlev filter.
Jon

2
Orijinal diziye referansı tutmanız gerekiyorsa değil.
Xotic750

Evet, orijinal diziye olan referansı saklamak istiyoruz.
novicePrgrmr

Sorunuz net değil, yaşadığınız asıl sorun nedir? Bir örnek verebilir misiniz, belki bir jsFiddle? Belki de kullanarak gerektiğini görünüyor indexziyade niteliğini itemşunlara aitsplice
Xotic750

@ Xotic750 Üzgünüm, açıklama eklendi.
novicePrgrmr

Yanıtlar:


246

Bunu yapmaya çalışıyor gibisin?

Array.prototype.splice kullanarak bir diziyi yineleyin ve değiştirin

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>

Bu, bitişik dizi öğeleriyle aynı değerlerden 2'sine sahip olmadığınız basit durumlarda iyi çalışır, diğer durumda bu sorunu yaşarsınız.

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>

Peki bir diziyi yinelerken ve değiştirirken bu problem hakkında ne yapabiliriz? Genel çözüm, tersine çalışmaktır. ES3'ü kullanırken tercih ederseniz şeker için kullanabilirsiniz

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>

Tamam, ancak ES5 yineleme yöntemlerini kullanmak istediniz. Pekala ve seçenek Array.prototype.filter kullanmak olacaktır, ancak bu orijinal diziyi değiştirmez, ancak yeni bir tane oluşturur, bu nedenle doğru yanıtı alabilseniz de, belirttiğiniz gibi görünmüyor.

ES5 Array.prototype.reduceRight'ı , iterasyon özelliği ile indirgeme özelliği için değil, yani ters yönde yineleme için de kullanabiliriz .

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>

Ya da ES5 Array.protoype.indexOf'u bu şekilde kullanabiliriz .

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>

Ama özellikle ES5 Array.prototype.forEach'i kullanmak istiyorsunuz , peki ne yapabiliriz? Peki biz kullanmaya gerek Array.prototype.slice dizinin yüzeysel bir kopyasını yapmak ve Array.prototype.reverse orijinal diziyi mutasyona ters çalışabilir böylece.

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>

Son olarak, ES6 bize sığ kopyalar yapıp tersine çevirmemize gerek kalmayan bazı başka alternatifler sunuyor. Özellikle Jeneratörleri ve Yineleyicileri kullanabiliriz . Ancak şu anda destek oldukça düşük.

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>

Yukarıdakilerin hepsinde dikkat edilmesi gereken bir şey , diziden NaN'yi çıkarıyorsanız , eşittir ile karşılaştırmanın işe yaramayacağıdır, çünkü Javascript NaN === NaNyanlıştır. Ancak çözümlerde, henüz belirlenmemiş başka bir uç durum olduğu için bunu göz ardı edeceğiz.

İşte elimizde, hala uç durumları olan çözümlerle daha eksiksiz bir yanıt var. İlk kod örneği hala doğrudur, ancak belirtildiği gibi sorunsuz değildir.


Cevabın için teşekkür ederim. Çözümünüzü kullanmayı denedim, ancak yine de diziden öğeyi kaldırmıyor. Ayrıntıları soruya koyacağım.
novicePrgrmr

Örneğimdeki gibi, console.log(review);arkasına koyun forEach.
Xotic750

4
Dikkatli olun, eğer iki ardışık öğe silinirse bu durum bozulur: var review = ['a', 'a', 'c', 'b', 'a']; ['a', 'c', 'b']
sonucunu verecek

4
NOT - Bu cevap YANLIŞ! Foreach diziyi dizine göre yineler. Aşağıdaki öğelerin dizinini yinelerken öğeleri sildikten sonra değişir. Bu örnekte, ilk "a" yı sildiğinizde, dizin numarası 1 artık "c" olur. Bu nedenle ilk 'b' bile değerlendirilmez. Silmeye çalışmadığına göre, her şey yolunda gitti, ama yol bu değil. Dizinin ters kopyasını yinelemeli ve ardından orijinal dizideki öğeleri silmelisiniz.
danbars

4
@ Xotic750 - orijinal cevap (şimdi ilk kod pasajıdır) yanlıştır çünkü önceki yorumda açıkladığım gibi forEach dizideki tüm öğeler arasında döngü yapmayacaktır. Sorunun bir forEach döngüsündeki öğelerin nasıl kaldırılacağı olduğunu biliyorum, ancak basit yanıt, bunu yapmamanızdır. Pek çok kişi bu cevapları okuduğundan ve çoğu zaman körü körüne cevapları (özellikle kabul edilen cevapları) kopyaladığından, koddaki kusurları not etmek önemlidir. Ters
dönme

37

Array.prototype.filterBunun yerine kullanın 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);

13

Her ne kadar Xotic750 cevabı birkaç iyi puan ve olası çözümler sunulur, bazen basit iyidir .

Yinelenen dizinin yinelemenin kendisinde mutasyona uğradığını biliyorsunuz (yani bir öğeyi kaldırmak => dizin değişiklikleri), bu nedenle en basit mantık, eski moda for(à la C dili) geri gitmektir :

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

Eğer gerçekten düşünürseniz, bir döngü forEachiçin sadece sözdizimsel şekerdir for... Yani size yardımcı olmuyorsa, lütfen kafanızı ona karşı kırmayı bırakın.


1

Bunu yapmak için indexOf'u da kullanabilirsiniz.

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

1

Bir koşul kullanarak diziden kaldırmak istediğinizi ve diziden öğeleri kaldırılan başka bir diziye sahip olmak istediğinizi anladım. Doğrudur?

Buna ne dersin?

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

Umarım bu yardımcı olur ...

Bu arada, 'for-loop'u' forEach 'ile karşılaştırdım.

Bir dizenin 'f' içermesi durumunda kaldırılırsa, sonuç farklıdır.

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

Ve her yinelemeyle kaldırın, sonuç da farklıdır.

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

Aşağıdakiler size özel karakterlerinize eşit olmayan tüm öğeleri verecektir!

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

0

İşte bunu nasıl yapmalısınız:

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

1
Durumun bu olduğunu sanmıyorum. Kodumu p'nin bir dizin olduğunu varsayarak değiştirdim ve şimdi ififadeye bile girmiyor .
novicePrgrmr

3
Görmeliydin @WhoCares Spec ecma-international.org/ecma-262/5.1/#sec-15.4.4.18 geri çağırma işlevi argümanlar vardıritem, index, object
Xotic750
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.