Once I iterate over the users slice, I need to then remove some of the users from the slice based on some condition. I will be looping over this users slice many times, slowly removing some elements.
I know from other languages it isn't safe to remove items from a collection while you are looping. So what I am doing is storing the elements I want removed in a map toMutate
. Once my original loop is finished, I then go ahead and try to remove the elements from the slice.
toMutate := make(map[int]User, 100)
for idx, u := range c.users {
if someCondition {
toMutate[idx] = u
}
}
I then call this function to remove the items from the user's slice.
for idx, u := range toMutate {
c.users = append(c.users[:idx], c.users[idx+1:]...)
}
Now I get an error:
panic: runtime error: slice bounds out of range
I think I know why I am getting the error. Each iteration I am removing an element from the slice. So now my idx value is off since the # of items has changed.
How do you deal with situations like this?
The genera idea goes as following:
toMutate := []int {}
for idx := range c.users {
if someCondition {
toMutate = append(toMutate, idx)
}
}
//...
sort.Sort(sort.Reverse(sort.IntSlice(toMutate)))
//...
for _, u := range toMutate {
c.users = append(c.users[:u], c.users[u+1:]...)
}
I think this is more efficient than the holding it in map, and re-slicing, for every value to remove.
func updateUser(users []User) []User {
temp := make([]User, 0, len(users))
for _, u := range users {
if !condition(u) {
temp = append(temp, u)
}
}
return temp
}
But something which would be more better is to use some other data structure, like linked list or something which is optimized for deletes.
Arrays(slices) aren't efficient for removing elements in between.