删除切片中的每个元素

时间:2015-03-26 21:27:06

标签: go

当我尝试循环切片并删除序列中的每个元素以打印其余元素时,我会使用SliceTricks中建议的删除方法获得一些意外行为。例如,当我尝试循环包含字母[A B C]的切片时,我希望输出按顺序为[B C][A C][A B]

方法1

package main

import "fmt"

func main() {
    a := []string {"A", "B", "C"}
    for i, _ := range a {
        fmt.Println(append(a[:i], a[i+1:]...))
    }
}

然而,这里的输出对我来说是令人惊讶的。它输出[B C]三次。

通过执行以下操作,我最终得到了预期的行为:

方法2

package main

import "fmt"

func main() {
    a := []string {"A", "B", "C"}
    for i, _ := range a {
        result := make([]string, 0)
        result = append(result, a[:i]...)
        result = append(result, a[i+1:]...)
        fmt.Println(result)
    }
}

在方法1中导致意外行为的原因是什么,除了方法2之外还有更好的方法来实现这个目标吗?

3 个答案:

答案 0 :(得分:5)

如果您想在没有额外分配的情况下执行此操作,请尝试更换显示的值in this example

请注意,这假设您可以随机播放列表内容。 如果没有,只需在循环之前复制一次列表,并执行以下操作。

package main

import "fmt"

func main() {
    set := []string{"a", "b", "c"}
    for i := range set {
        set[0], set[i] = set[i], set[0]
        fmt.Println(set[1:])
    }
}

输出:

[b c]
[a c]
[a b]

答案 1 :(得分:1)

“what”是因为append(slice, elems...)实际上是用新元素更新slice。它返回一个“新”切片只是因为它可能由于内存重新分配而不得不重新定位原始切片。因此,在您的示例代码中,您实际上每次调用a时都会更改append的内容。 (好的概述在this golang博客文章的“附加:示例”部分中。)

关于“如何”,我的尝试是:

package main

import "fmt"

func main() {
    a := []string {"A", "B", "C"}
    for i, _ := range a {
        result := make([]string, i, len(a)-1)
        copy(result, a[:i])
        result = append(result, a[i+1:]...)
        fmt.Println(result)
    }
}

DEMO

使用长度和容量初始化result,以及使用copy而不是两次append s尝试减少所需的内存重新分配次数。

答案 2 :(得分:0)

看看第一次迭代后会发生什么:

package main

import "fmt"

func main() {
    a := []string{"A", "B", "C"}
    x := append(a[:0], a[1:]...)
    fmt.Println(a)
    fmt.Println(x)
}

给予

[B C C]
[B C]

请参阅https://play.golang.org/p/2LqBwHejhy

接下来的两次迭代是相似的。试试吧。