1. ホーム
  2. javascript

[解決済み] forEachループで配列から要素を削除するには?

2022-06-15 07:53:33

質問

で配列の要素を削除しようとしています。 forEach ループで配列の要素を削除しようとしていますが、私が見てきた標準的な解決策で困っています。

これは私が現在試しているものです。

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

に入り込んでいるのは分かるのですが if に入り込んでいることがわかります。 YippeeeeeE!!!!!!!!!!!!! が表示されるからです。

MY PROBLEM: 私のforループとifロジックが健全であることは分かっていますが、配列から現在の要素を削除する試みは失敗しています。

UPDATEしてください。

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文に入っていますが、[- -]が残っていることも明らかです。

どうすれば解決するのか?

このようなことをしようとしているようですが?

配列の反復処理と変異を 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は浅いコピーを作成し、それを反転させる必要がない、いくつかのさらなる選択肢を提供しています。注目すべきは ジェネレータとイテレータ . しかし、現在のところサポートはかなり低いです。

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 を配列から取り除いた場合、等号での比較はうまくいきません。なぜなら、Javascriptでは NaN === NaN は偽だからです。しかし、それはまた別の未特定のエッジケースであるため、解決策ではそれを無視するつもりです。

これで、まだエッジケースがある解決策を含む、より完全な答えが得られました。一番最初のコード例はまだ正しいのですが、前述のように問題がないわけではありません。