Removing Elements from Arrays the Right Way
Imagine you’re working with a simple array, one that contains 16 integers.
const eg = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610];
Now, let’s say we need to weed out all numbers greater than 99 from our array. Sounds like a piece of cake, doesn’t it?
Your code will probably look like this,
|
|
But wait, once you print the updated array, you’ll notice something’s off.
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 233, 610];
Why are 233 and 610 still lounging in our array? They’re clearly above our cut-off of 99.
What went wrong?
Let’s sprinkle our code with log statements to see what’s happening under the hood. You can view and run the code at this link.
|
|
The output is,
index value array length
0 0 16
1 1 16
2 1 16
3 2 16
4 3 16
5 5 16
6 8 16
7 13 16
8 21 16
9 34 16
10 55 16
11 89 16
12 144 16
Element at 12 removed. Length is 15
13 377 15
Element at 13 removed. Length is 14
[ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 233, 610 ]
Here’s where it gets interesting. When our loop hits index 12, it encounters the number 144. 144 is removed, which reduces array length to 15 from 16.
Then the index i
is 14, and it reaches element 377. 377 is removed, which reduces array length from 15 to 14.
Then the index i
reaches 15, but it fails the condition i < eg.length
, which stops the result.
The loop ran only 14 times when it should have run 16 times. It happens because we modified the array length during the iteration.
Have a look at following incorrect code.
|
|
If you try to run this code, you will get “index out of bound” runtime errors.
Now, how do we solve this issue? We have three ways to do it the right way.
Solution 1 – Decrement index
One way to solve this problem is to decrement i
whenever an element from the array is removed. This way index does not skip over the remaining elements of the array.
|
|
Its output is
index value array length
0 0 16
1 1 16
2 1 16
3 2 16
4 3 16
5 5 16
6 8 16
7 13 16
8 21 16
9 34 16
10 55 16
11 89 16
12 144 16
Element at 12 removed. Length is 15
12 233 15
Element at 12 removed. Length is 14
12 377 14
Element at 12 removed. Length is 13
12 610 13
Element at 12 removed. Length is 12
[ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]
You can view and run this code here.
Solution 2 – Iterate in Reverse
In this solution, you start from the last element of the array and continue backwards. This way, even if array length is modified, the loop iterates over all the remaining elements.
|
|
Its output is
index value array length
15 610 16
Element at 15 removed. Length is 15
14 377 15
Element at 14 removed. Length is 14
13 233 14
Element at 13 removed. Length is 13
12 144 13
Element at 12 removed. Length is 12
11 89 12
10 55 12
9 34 12
8 21 12
7 13 12
6 8 12
5 5 12
4 3 12
3 2 12
2 1 12
1 1 12
0 0 12
[ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]
You can view and run this code here.
You can, of course, use a for
loop in place of while
.
for (i = eg.length - 1; i >= 0; i--) {}
You can view code with a for
loop here.
Is this problem specific to some languages?
No! Whichever programming language you pick, if you iterate and remove array elements incorrectly, you will face this issue.
Here is the same problem replicated in Golang. If you run it, the program fails during runtime.
|
|
The output of the above program:
./main
15
14
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
main.remove(...)
/home/runner/main.go:6
main.main()
/home/runner/main.go:14 +0x25b
exit status 2
But if we turn around the code and start iteration is reverse, then the code works fine.
|
|
Best Solution
A succinct solution is to use functional programming.
Most modern programming languages are incorporating functional programming features. Thus, if a language supports new methods, you do not have to use the old fashioned loops to remove elements from an array.
In ECMA-262 5th edition, filter()
method was added to the JavaScript.
We can rework the above example into a simple oneliner.
|
|
Here is a working Python oneliner.
|
|
Either of the following way will work in C#.
|
|
|
|
C++ has std::remove_if
method.
|
|
You can run this code here.