Remova itens do Array enquanto itera sobre ele.

Você já encontrou resultados inesperados quando os itens são removidos de uma matriz enquanto a matriz está sendo iterada? Isso pode parecer familiar:

var numbers = [17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16],
i
;

for (i=0; i < numbers.length; ++i) {
if (numbers[i] % 2 === 0) {
numbers
.splice(i, 1); // Remove even numbers
}
}

console
.log(numbers); // [17, 14, 15, 8, 7, 1, 9, 19, 3, 5, 6]
// WTF: ^ ^ ^

O que está acontecendo aqui? Você notará que os números pares que não foram removidos foram precedidos por outro número par.

Depois spliceé chamado, o item no índice ié agora o que era o próximo item na lista, então o para gatilhos de loop ++i, que salta para o próximo item de lado, deixando
um item desmarcada. Assista com atenção:

[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 0
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 1
X

[17, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 2; skipped `14`
^
[17, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 3
X

[17, 14, 15, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 4; skipped `8`
^
[17, 14, 15, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 5
^
[17, 14, 15, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 6
^
[17, 14, 15, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 7
^
[17, 14, 15, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 8
^
[17, 14, 15, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 9
X

[17, 14, 15, 8, 7, 1, 9, 19, 3, 5, 4, 6, 16] // i = 10; skipped `5`
X

[17, 14, 15, 8, 7, 1, 9, 19, 3, 5, 6, 16] // i = 11; skipped `6`
X

[17, 14, 15, 8, 7, 1, 9, 19, 3, 5, 6] // End result.

A solução mais “óbvia” aqui é simplesmente diminuir isempre que um item for removido:

for (i=0; i < numbers.length; ++i) {
if (numbers[i] % 2 === 0) {
numbers
.splice(i, 1); // Remove even numbers
--i; // Correct the index value
}
}

Mas nós podemos fazer melhor. Simplesmente percorrendo a matriz ao contrário , evitamos totalmente o problema.

for (i = numbers.length - 1; i >= 0; --i) {
if (numbers[i] % 2 === 0) {
numbers
.splice(i, 1); // Remove even numbers
}
}

Agora, sempre que um item é removido, i“cai” automaticamente para o item correto. Ver:

[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6, 16] // i = 15
X

[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4, 6] // i = 14
X

[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5, 4] // i = 13
X

[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5] // i = 12
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 18, 5] // i = 11
X

[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 5] // i = 10
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 5] // i = 9
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 5] // i = 8
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 5] // i = 7
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 5] // i = 6
^
[17, 2, 14, 15, 20, 8, 7, 1, 9, 19, 3, 5] // i = 5
X

[17, 2, 14, 15, 20, 7, 1, 9, 19, 3, 5] // i = 4
X

[17, 2, 14, 15, 7, 1, 9, 19, 3, 5] // i = 3
^
[17, 2, 14, 15, 7, 1, 9, 19, 3, 5] // i = 2
X

[17, 2, 15, 7, 1, 9, 19, 3, 5] // i = 1
X

[17, 15, 7, 1, 9, 19, 3, 5] // i = 0; done!
^