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 i
sempre 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!
^