删除切片中的每个元素

huangapple go评论94阅读模式
英文:

Removing each element in a slice

问题

当您尝试通过循环遍历切片并按顺序删除每个元素以打印剩余元素时,使用SliceTricks中建议的Delete方法时,您遇到了一些意外行为。例如,当您尝试循环遍历包含字母[A B C]的切片时,您期望的输出顺序是[B C][A C][A B]

在方法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之外,是否有更好的方法来实现这个目标?

英文:

I'm getting some unexpected behavior when I try to loop through a slice and remove every element in sequence to print the remaining elements, using the suggested Delete method from SliceTricks. For example, when I try and loop through a slice that contains the letters [A B C], I expect the output to be [B C], [A C], [A B] in that order:

Method 1

package main

import "fmt"

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

However, the output here is surprising to me. It outputs [B C] three times.

I did eventually get my expected behavior by doing the following:

Method 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)
	}
}

What is causing the unexpected behavior in method 1 and is there a better way to achieve this other than method 2?

答案1

得分: 5

如果你想在不进行额外分配的情况下完成操作,可以尝试按照以下示例中所示的方式交换值:

请注意,这假设你可以接受打乱列表内容。如果不行,只需在循环之前复制一次列表,然后执行与下面相同的操作。

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]
英文:

If you want to do it without extra allocations, try just swapping out values as shown in this example:

Note that this assumes you are OK with shuffling the list contents.
If not, just copy the list once before the loop and do the same as below.

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:])
	}
}

Output:

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

答案2

得分: 1

"what"是因为append(slice, elems...)实际上是用新元素更新了slice。它之所以返回一个"新"的切片,是因为它可能需要重新分配内存来重新定位原始切片。所以,在你的示例代码中,每次调用append时,你实际上是改变了a的内容。(关于这个问题的一个很好的概述可以在golang博客文章的"Append: An Example"部分找到)。

至于"how",我尝试的代码如下:

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,试图减少所需的内存重新分配次数。

英文:

The "what" is because append(slice, elems...) is actually updating the slice with the new elements. It returns a "new" slice only because it may have had to relocate the original slice due to memory reallocation. So, in your example code, you are actually changing the contents of a with each call to append. (A good overview is in the "Append: An Example" section of this golang blog post).

As to "how", my attempt is:

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

Initializing result with a length and capacity, as well as using copy instead of two appends attempts to reduce the number of memory reallocations required.

答案3

得分: 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

接下来的两次迭代类似。你可以试一试。

英文:

See what happens after the first iteration:

package main

import "fmt"

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

Gives

[B C C]
[B C]

See https://play.golang.org/p/2LqBwHejhy

The next two iterations are similar. Just try it out.

huangapple
  • 本文由 发表于 2015年3月27日 05:27:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/29289198.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定