For a personal project, I did something like this:
func filter(sl []int, fn func(int) bool) []int { result := make([]int, 0, len(sl)) last := 0 for i, v := range sl { if fn(v) { result = append(result, sl[last:i]...) last = i + 1 } } return append(result, sl[last:]...) }
It doesn't mutate the original, but should be relatively efficient. It's probably better to just do:
func filter(sl []int, fn func(int) bool) (result []int) { for _, v := range sl { if !fn(v) { result = append(result, v) } } return }
Simpler and cleaner. If you want to do it in-place, you probably want something like:
func filter(sl []int, fn func(int) bool) []int { outi := 0 res := sl for _, v := range sl { if !fn(v) { res[outi] = v outi++ } } return res[0:outi] }
You can optimize this to use copy to copy ranges of elements, but that's twice the code and probably not worth it.
So, in this specific case, I'd probably do something like:
func deleteRecords(l []*Record, ids []int) []*Record { outi := 0 L: for _, v := range l { for _, id := range ids { if v.id == id { continue L } } l[outi] = v outi++ } return l[0:outi] }
(Note: untested.)
No allocations, nothing fancy, and assuming the rough size of the list of Records and the list of ids you presented, a simple linear search is likely to do as well as fancier things but without any overhead. I realize that my version mutates the slice and returns a new slice, but that's not un-idiomatic in Go, and it avoids forcing the slice at the callsite to be heap allocated.