forEach 루프의 배열에서 요소를 제거하는 방법은 무엇입니까?


97

forEach루프 의 배열에서 요소를 제거하려고하는데 내가 본 표준 솔루션에 문제가 있습니다.

이것이 내가 현재 시도하고있는 것입니다.

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

콘솔에서 if보고 있기 때문에 안으로 들어가는 것을 알고 있습니다 YippeeeeeE!!!!!!!!!!!!!.

내 문제 : for 루프와 논리가 건전하다는 것을 알고 있지만 배열에서 현재 요소를 제거하려는 시도가 실패했습니다.

최신 정보:

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입니다.
Jon

2
원래 배열에 대한 참조를 유지해야하는 경우에는 그렇지 않습니다.
Xotic750

예, 원래 배열에 대한 참조를 유지하고 싶습니다.
novicePrgrmr

질문에서 명확하지 않습니다. 실제로 겪고있는 문제는 무엇입니까? 예를 들어, 아마도 jsFiddle? 당신이 아마 사용되어야한다는 것 index보다는 속성을 item당신을위한splice
Xotic750

@ Xotic750 죄송합니다. 설명이 추가되었습니다.
novicePrgrmr

답변:


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.reverse 의 얕은 복사본을 만들기 위해 Array.prototype.slice 를 사용해야 합니다. 그러면 원래 배열을 변경하기 위해 반대로 작업 할 수 있습니다.

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 을 제거하는 경우 Javascript NaN === NaN에서 거짓 이기 때문에 같음과 비교하는 것이 작동하지 않는다는 것 입니다. 그러나 우리는 아직 명시되지 않은 또 다른 엣지 케이스이므로 솔루션에서 그것을 무시할 것입니다.

그래서 우리는 여전히 엣지 케이스가있는 솔루션으로 더 완전한 답을 얻었습니다. 첫 번째 코드 예제는 여전히 정확하지만 언급했듯이 문제가없는 것은 아닙니다.


대답 해줘서 고마워. 솔루션을 사용해 보았지만 여전히 배열에서 요소를 제거하지 않습니다. 질문에 세부 사항을 기재하겠습니다.
novicePrgrmr 2014-07-17

내 예와 같이 console.log(review);뒤에 넣으십시오 forEach.
Xotic750

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의 답변 은 몇 가지 좋은 점과 가능한 솔루션을 제공 하지만 때로는 간단한 것이 더 좋습니다 .

반복되는 배열이 반복 자체에서 변경된다는 것을 알고 있습니다 (즉, 항목 제거 => 인덱스 변경). 따라서 가장 간단한 논리는 구식 for( 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());

당신이 그것에 대해 정말로 생각한다면, a forEachfor루프를 위한 문법적 설탕 일뿐입니다 ... 그래서 그것이 당신을 돕지 않는다면, 그것에 대해 머리를 부수 지 마십시오.


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

0

방법은 다음과 같습니다.

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

1
나는 그렇지 않다고 생각한다. p가 인덱스라고 가정하고 코드를 변경했는데 이제는 if성명에 들어 가지 않습니다 .
novicePrgrmr

3
당신은 볼 수 @WhoCares 사양 ecma-international.org/ecma-262/5.1/#sec-15.4.4.18 콜백 함수의 인수는item, index, object
Xotic750
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.