在Go中迭代时,从切片中删除条目

Kyl*_*ndt 25 go

在覆盖切片时从切片中移除项目的最佳方法是什么?

例如:

type MultiDataPoint []*DataPoint

func (m MultiDataPoint) Json() ([]byte, error) {
    for i, d := range m {
        err := d.clean()
        if ( err != nil ) {
            //Remove the DP from m
        }
    }
    return json.Marshal(m)
}
Run Code Online (Sandbox Code Playgroud)

tom*_*asz 39

正如您在其他地方提到的那样,您可以分配新的内存块并仅将有效元素复制到其中.但是,如果要避免分配,可以就地重写切片:

i := 0 // output index
for _, x := range s {
    if isValid(x) {
        // copy and increment index
        s[i] = x
        i++
    }
}
s = s[:i]
Run Code Online (Sandbox Code Playgroud)

完整示例:http://play.golang.org/p/FNDFswPeDJ

请注意,它会i在基础数组中的索引之后留下一些垃圾,因此请确保没有其他切片使用elswhere.

  • @Ectomorph:固定; 那时我是C ++程序员–幸运的是,这些天已经过去,并接受了分号。 (4认同)

Mic*_*ael 14

可能有更好的方法,但这是一个从切片中删除偶数值的示例:

m := []int{1,2,3,4,5,6}

deleted := 0
for i := range m {
    j := i - deleted
    if (m[j] & 1) == 0 {
        m = m[:j+copy(m[j:], m[j+1:])]
        deleted++
    } 
}
Run Code Online (Sandbox Code Playgroud)

请注意,我没有使用i, d := range m语法获取元素,因为d一旦开始从切片中删除,最终会被设置为错误的元素.

  • 虽然我刚刚意识到创建第二个MultiDataPoint对象是非常直接的(可能效率不高?),但是要向它添加有效的东西,并且Marshal那个.不知道我怎么没有看到这一点: - / (2认同)
  • 你应该使用`for i:= 0; 我<len(m); i ++ {`对于循环,范围可能会给你一个`索引超出范围'错误. (2认同)

aut*_*tic 12

我知道很久以前的答案,但我在其他语言中使用这样的东西,但我不知道它是否是golang方式.

只需从后向前迭代,这样您就不必担心被删除的索引.我使用与Adam相同的例子.

m = []int{3, 7, 2, 9, 4, 5}

for i := len(m)-1; i >= 0; i-- {
    if m[i] < 5 {
        m = append(m[:i], m[i+1:]...)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 但是,如果删除多于1个元素,则效率不高.它为每个被删除的元素复制数组.从10'000个元素中删除100个复制500'000(平均)元素.其中@tomasz解决方案复制10'000.快了50倍. (4认同)
  • 最简单的答案,应该是最重要的答案 (3认同)

Ada*_*m B 6

另一个选项是使用切片长度的正常for循环,并在每次删除值时从索引中减去1.请参阅以下示例:

m := []int{3, 7, 2, 9, 4, 5}

for i := 0; i < len(m); i++ {
    if m[i] < 5 {
        m = append(m[:i], m[i+1:]...)
        i-- // -1 as the slice just got shorter
    }
}
Run Code Online (Sandbox Code Playgroud)

我不知道是否len()使用了足够的资源来做出任何改变,但你也可以只运行一次并从长度值中减去:

m := []int{3, 7, 2, 9, 4, 5}

for i, s := 0, len(m); i < s; i++ {
    if m[i] < 5 {
        m = append(m[:i], m[i+1:]...)
        s--
        i--
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好问题,但我不记得为什么它在那里.可能只是为了演示某种功能作为演示用例. (2认同)

小智 6

这是从切片中删除元素的更惯用的 Go 方法。

temp := s[:0]
for _, x := range s {
    if isValid(x) {
        temp = append(temp, x)
    }
}
s = temp
Run Code Online (Sandbox Code Playgroud)

游乐场链接:https : //play.golang.org/p/OH5Ymsat7s9

注意:示例和游乐场链接基于@tomasz 的回答/sf/answers/1438578151/