6

我想以就地方式从集合中删除元素。考虑以下代码段:

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

令人惊讶的结果是:final a [1 3 5 7 9 10 10 10 10 10]

我想知道如何做到这一点。我很确定接收器需要是指向Ints. 但这会使代码有些混乱(*xs可能在任何地方都添加括号),但更重要的是它会产生相同的结果。

4

3 回答 3

2

我会通过移动元素,然后调整切片大小并使用指针来做到这一点。像这样的东西:

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)
}
于 2014-07-14T09:45:31.430 回答
1

您必须在此处使用指针。如果您不喜欢在每个地方添加 *xs,只需使用临时变量来执行所有操作,然后将其设置回来。这是代码http://play.golang.org/p/eAFkV3Lwh6

于 2014-07-14T10:55:51.673 回答
1

您的代码几乎是正确的。

第一个错误是i++您在删除元素时需要避免这样做,否则会i++跳过下一个未读元素。这就是为什么我把它放在else从句中。

第二个错误是它xsFilter函数的局部变量,因此如果您更改它指向的内容 (with xs = ...),则不会更改a指向 inside 的内容main*xs您可以通过将其设为指针(正如其他人发布的那样)或返回新的过滤切片来解决此问题,如下所示。

package main

import "fmt"

type Ints []int

func (xs Ints) Filtered() Ints {
    for i := 0; i < len(xs); {
        if xs[i]%2 == 0 {
            xs = append(xs[:i], xs[i+1:]...)
        } else {
            i++
        }
    }
    return xs
}

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

http://play.golang.org/p/Nre7w4KQ78

于 2014-07-14T13:42:35.590 回答