Search code examples
goslicein-place

In place deletion of Golang slice elements


I want to delete elements from a collection in an in-place manner. Consider the following snippet:

package main

import "fmt"

type Ints []int

func (xs Ints) Filter() {
    for i := 0; i < len(xs); i++ {
        if xs[i]%2 == 0 { // Or some other filtering function
             xs = append(xs[:i], xs[i+1:]...)
        }
        fmt.Printf("i %+v\n", i)
        fmt.Printf("xs %+v\n", xs)
    }
}

func main() {
    a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})

    fmt.Printf("initial a %+v\n", a)

    a.Filter()

    fmt.Printf("final a %+v\n", a)
}

http://play.golang.org/p/1nL6Il2Gf1

The surprising result is: final a [1 3 5 7 9 10 10 10 10 10]

I wonder how to do this. I'm pretty sure the receiver needs to be a pointer to Ints. But that messes up the code somewhat (adding *xs everywhere possibly with brackets) but more importantly it yields the same result.


Solution

  • I'd do it by moving elements, then resizing the slice, and using a pointer. Something like this:

    package main
    
    import "fmt"
    
    type Ints []int
    
    func (xs *Ints) Filter() {
        filterPos := 0
        for i := 0; i < len(*xs); i++ {
            if (*xs)[i]%2 == 0 { // Or some other filtering function
                 (*xs)[filterPos] = (*xs)[i]
             filterPos++
            }
        }
        (*xs) = (*xs)[:filterPos]
    }
    
    func main() {
        a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
    
        fmt.Printf("initial a %+v\n", a)
    
        a.Filter()
    
        fmt.Printf("final a %+v\n", a)
    }