Remove items from Array while iterating over it.
Ever encounter unexpected results when items are removed from an array while the array is being iterated over? This might look 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: ^ ^ ^
What's going on here? You'll notice that the even numbers that didn't get removed were each preceded by another even number.
After splice
is called, the item at index i
is now what was the next item in the list, then the for loop triggers ++i
, which skips to the next next item, leaving
an item unchecked. Watch carefully:
[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.
The most "obvious" solution here is to simply decrement i
whenever an item is removed:
for (i=0; i < numbers.length; ++i) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1); // Remove even numbers
--i; // Correct the index value
}
}
But we can do better. Simply by walking through the array in reverse, we avoid the issue entirely.
for (i = numbers.length - 1; i >= 0; --i) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1); // Remove even numbers
}
}
Now, whenever an item is removed, i
automatically "falls" to the correct item. Watch:
[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!
^
Written by Louis Acresti
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Algorithms
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#