删除切片中的元素

时间:2014-07-29 21:36:36

标签: go

func main() {
    a := []string{"Hello1", "Hello2", "Hello3"}
    fmt.Println(a)
    // [Hello1 Hello2 Hello3]
    a = append(a[:0], a[1:]...)
    fmt.Println(a)
    // [Hello2 Hello3]
}

这个删除技巧如何与追加功能一起工作?

似乎它抓住了第一个元素(空数组)之前的所有内容

然后在第一个元素(位置零)

之后追加所有内容

......(点点)是做什么的?

7 个答案:

答案 0 :(得分:250)

其中a是切片,i是您要删除的元素的索引:

a = append(a[:i], a[i+1:]...)

...是Go中可变参数的语法。

基本上,当定义一个函数时,它会将您传递的所有参数放入该类型的一个切片中。通过这样做,您可以根据需要传递任意数量的参数(例如,fmt.Println可以根据需要使用尽可能多的参数。)

现在,当调用一个函数时,...执行相反的操作:它解压缩一个切片并将它们作为单独的参数传递给一个可变参数函数。

这一行是做什么的:

a = append(a[:0], a[1:]...)

基本上是:

a = append(a[:0], a[1], a[2])

现在,你可能想知道,为什么不做呢

a = append(a[1:]...)

嗯,append的函数定义是

func append(slice []Type, elems ...Type) []Type

所以第一个参数必须是正确类型的切片,第二个参数是可变参数,所以我们传入一个空切片,然后解压缩切片的其余部分以填充参数。

答案 1 :(得分:42)

有两种选择:

答:你关心保留数组顺序:

a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]

B:你不关心保留订单(这可能更快):

a[i] = a[len(a)-1] // Replace it with the last one. CAREFUL only works if you have enough elements.
a = a[:len(a)-1]   // Chop off the last one.

如果您的数组是指针,请参阅链接以查看内存泄漏的影响。

https://github.com/golang/go/wiki/SliceTricks

答案 2 :(得分:7)

与其将[a:]-,[:b]-和[a:b]-标记中的索引视为元素索引,不如将它们视为元素周围和元素之间的间隙的索引,从索引为0的元素之前的索引为0的间隙开始。

enter image description here

仅查看蓝色数字,就更容易了解发生了什么:[0:3]将所有内容括起来,[3:3]为空,而[1:2]将产生{"B"}。然后[a:]只是[a:len(arrayOrSlice)]的简短版本,[:b][0:b]的简短版本,[:][0:len(arrayOrSlice)]的简短版本。后者通常用于在需要时将数组变成切片。

答案 3 :(得分:5)

...是可变参数的语法。

我认为它是由编译器使用slice([]Type)实现的,就像函数append一样:

func append(slice []Type, elems ...Type) []Type

当你在“追加”中使用“elems”时,实际上它是一个切片([]类型)。 所以“a = append(a[:0], a[1:]...)”表示“a = append(a[0:0], a[1:])

a[0:0]是一个没有任何内容的切片

a[1:]是“Hello2 Hello3”

这就是它的工作原理

答案 4 :(得分:3)

在golang的wiki中,它会显示切片的一些技巧,包括从切片中删除一个元素。

链接:enter link description here

例如,a是要删除数字i元素的切片。

a = append(a[:i], a[i+1:]...)

OR

a = a[:i+copy(a[i:], a[i+1:])]

答案 5 :(得分:2)

或者,因为您正试图找到要删除的元素的索引,

{{1}}

好吧没关系。对于该主题的正确答案,但问题正确的答案是错误的。

答案 6 :(得分:0)

使用可接受的答案解决方案,我得到的索引超出范围错误。 原因: 范围开始时,不是一个一个地迭代值,而是一个索引迭代。 如果在切片处于范围内时对其进行了修改,则会引起一些问题。

旧答案:

chars := []string{"a", "a", "b"}

for i, v := range chars {
    fmt.Printf("%+v, %d, %s\n", chars, i, v)
    if v == "a" {
        chars = append(chars[:i], chars[i+1:]...)
    }
}
fmt.Printf("%+v", chars)

预期:

[a a b], 0, a
[a b], 0, a
[b], 0, b
Result: [b]

实际:

// Autual
[a a b], 0, a
[a b], 1, b
[a b], 2, b
Result: [a b]

正确的方法(解决方案):

chars := []string{"a", "a", "b"}

for i := 0; i < len(chars); i++ {
    if chars[i] == "a" {
        chars = append(chars[:i], chars[i+1:]...)
        i-- // form the remove item index to start iterate next item
    }
}

fmt.Printf("%+v", chars)

来源:https://dinolai.com/notes/golang/golang-delete-slice-item-in-range-problem.html