英文:
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)
}
}
通过使用指定长度和容量来初始化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)
}
}
Initializing result
with a length and capacity, as well as using copy
instead of two append
s 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论