Removing item(s) from a slice, while iterating in Go
How easy would it be to remove item(s) from a slice, while iterating that slice? It seems to be a trivial task, so lets see how to accomplish this in Go programming language.
Coming from a Java landscape, I do remember that in Java you cannot remove items from a list directly. For example, following code will throw ConcurrentModificationException:
1 |
|
Java provides Iterator.remove() method for such purposes.
Ok, no more Java, let’s see how to do this in Go. First of to remove an item from a slice you need to use built-in function append:
1 |
|
Given the following code:
1 |
|
Let’s try to remove P3
person, while iterating the people
slice with range
loop:
1 |
|
Looks like it works with single item marked to remove, but it will fail soon with panic: runtime error: slice bounds out of range, if there are more than one item to remove. This happens because the length of the people
slice is decreasing with each successful remove operation. But the range
loop iterates the initial len(people)
times.
Now it is clear that we need to keep track of len(people)
with each successful
remove operation. Let’s try to accomplish this with plain old for loop:
1 |
|
Well now it works! But why to keep extra counter rcount
to track the number of remove operations, if we know that the length of people
slice is decreasing with each successful remove operation?
Bearing that in mind we can optimize to something like this:
1 |
|
But it still looks ugly, isn’t it? Well as a general rule of thumb, if something looks ugly, try to do it the opposite way. Why not? Let’s try:
1 |
|
Now, this version is clean and fully functional. Hope you find this useful.
Update: 26.04.2018
Following is simpler way to filter a slice without allocating a new underlying array:
1 |
|
Recommended further reading: Slice expressions in Go