如何重复地从切片中删除一个元素?

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

How to remove an item from a slice repeatedly?

问题

我想从一个数组中创建多个切片,每个切片都缺少一个元素。我正在使用以下代码(playground):

nums := []int{1,2,3}
for i := 0; i < len(nums); i++ {
    fmt.Println(append(nums[:i], nums[i+1:]...))
}

我期望得到的结果是:

[2 3]
[1 3]
[1 2]

但实际上我得到的结果是:

[2 3]
[2 3]
[2 3]

为什么会这样呢?

英文:

I would like to create multiple slices from one array. One slice each with one element missing. I am using this code (playground):

nums := []int{1,2,3}
for i := 0; i &lt; len(nums); i++ {
    fmt.Println(append(nums[:i], nums[i+1:]...))
}

I was expecting to receive

[2 3]
[1 3]
[1 2]

But instead I receive

[2 3]
[2 3]
[2 3]

Why is that?

答案1

得分: 1

非常感谢你向我指出这个问题。这是我的当前解决方案。它简单地复制了我正在处理的数组(playground)。

package main

import (
	"fmt"
)

func main() {
	nums := []int{1,2,3}
        for i := 0; i < len(nums); i++ {
	        cpy := make([]int, len(nums))
	        copy(cpy, nums)
            fmt.Println(append(cpy[:i], cpy[i+1:]...))
        }
}
英文:

Thank you very much for pointing this out to me. This is my current solution. It simply copies the array on which I am working (playground)

package main

import (
	&quot;fmt&quot;
)

func main() {
	nums := []int{1,2,3}
        for i := 0; i &lt; len(nums); i++ {
	        cpy := make([]int, len(nums))
	        copy(cpy, nums)
            fmt.Println(append(cpy[:i], cpy[i+1:]...))
        }
}

答案2

得分: 1

正文翻译如下:

正如 mkopriva 正确指出的那样,你的程序输出与你期望的不同,因为所有由 append 生成的切片共享相同的底层数组。你需要以某种方式将这些切片与切片 nums 的底层数组解耦。

一种可行的方法确实是使用 copy,就像你在 你的答案 中所做的那样。还有一种更简洁的替代方法,尽管对于未经训练的人来说可能不太清晰。

与其使用 copy,你可以将 nums[:i:i](一个完整切片表达式,也称为三索引切片)作为 append 的第一个参数:

nums := []int{1,2,3}
for i := 0; i < len(nums); i++ {
  fmt.Println(append(nums[:i:i], nums[i+1:]...))
}

生成的切片将与切片 nums 的底层数组解耦,你将获得期望的输出:

[2 3]
[1 3]
[1 2]

(Playground)

自 Go 1.18 起,你可以使用 golang.org/x/exp/slices 中的 CloneDelete 函数以更可读的方式实现相同的结果:

func main() {
  nums := []int{1, 2, 3}
  for i := 0; i < len(nums); i++ {
    fmt.Println(slices.Delete(slices.Clone(nums), i, i+1))
  }
}

(Playground)

英文:

As mkopriva correctly pointed out, the output of your program differs from what you expect because all slices resulting from append share the same underlying array. You need to somehow decouple those slices from the underlying array of slice nums.

One viable approach is indeed to use copy, as you did in your answer. There is a more concise alternative, although it may not be clearer to untrained eyes.

Rather than resorting to copy, you can use nums[:i:i] (a full-slice expression, a.k.a. three-index slice) as the first argument of append:

nums := []int{1,2,3}
for i := 0; i &lt; len(nums); i++ {
  fmt.Println(append(nums[:i:i], nums[i+1:]...))
}

The resulting slice will be decoupled from slice nums's underlying array and you'll get the desired output:

[2 3]
[1 3]
[1 2]

(Playground)

Since Go 1.18, you can use functions Clone and Delete from the golang.org/x/exp/slices package to achieve the same result in an arguably more readable fashion:

func main() {
  nums := []int{1, 2, 3}
  for i := 0; i &lt; len(nums); i++ {
    fmt.Println(slices.Delete(slices.Clone(nums), i, i+1))
  }
}

(Playground)

huangapple
  • 本文由 发表于 2021年7月11日 22:07:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/68336955.html
匿名

发表评论

匿名网友

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

确定