Go 删除切片中的元素

Go 删除切片中的元素,go,Go,这个带有append函数的删除技巧是如何工作的 它似乎在抓取第一个元素(空数组)之前的所有内容 然后在第一个元素之后追加所有内容(位置零) 什么是。。。(dot-dot)do?其中a是切片,i是要删除的元素的索引: func main() { a := []string{"Hello1", "Hello2", "Hello3"} fmt.Println(a) // [Hello1 Hello2 Hello3] a = append(a[:0], a[1:]...)

这个带有append函数的删除技巧是如何工作的

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

然后在第一个元素之后追加所有内容(位置零)


什么是。。。(dot-dot)do?

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

func main() {
    a := []string{"Hello1", "Hello2", "Hello3"}
    fmt.Println(a)
    // [Hello1 Hello2 Hello3]
    a = append(a[:0], a[1:]...)
    fmt.Println(a)
    // [Hello2 Hello3]
}
是Go中可变参数的语法

基本上,定义函数时,它会将传递的所有参数放入该类型的一个切片中。通过这样做,您可以传递任意数量的参数(例如,
fmt.Println
可以接受任意数量的参数)

现在,当调用函数时,
的作用正好相反:它解压一个切片,并将其作为单独的参数传递给变量函数

这条线的作用是:

a = append(a[:i], a[i+1:]...)
基本上是:

a = append(a[:0], a[1:]...)
现在,你可能会想,为什么不这样做呢

a = append(a[:0], a[1], a[2])
那么,
append
的函数定义是

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

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

。。。是可变参数的语法

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

func append(slice []Type, elems ...Type) []Type
当您在“append”中使用“elems”时,实际上它是一个切片([]类型)。 所以“
a=append(a[:0],a[1:]…)
”意味着“
a=append(a[0:0],a[1:])

a[0:0]
是一个什么都没有的片

a[1:][/code>是“Hello2 Hello3”

这就是它的工作原理有两种选择:

答:您关心的是保留数组顺序:

func append(slice []Type, elems ...Type) []Type
B:你不在乎保留订单(这可能更快):

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


在golang的wiki中,它展示了slice的一些技巧,包括从slice中删除元素

链接:

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

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.


不要将
[a://code>-、
[:b]
-和
[a:b]
-符号中的索引视为元素索引,而应将它们视为元素周围和元素之间间隙的索引,从间隙索引
0
开始,然后将元素索引为
0


只看蓝色的数字,就更容易看到发生了什么:
[0:3]
包含所有内容,
[3:3]
为空,
[1:2]
将产生
{“B”}
。然后
[a::
只是
[a:len(arrayorsicle)]
的短版本,
[:b]
[0:b]
的短版本,
[:]
[0:len(arrayorsicle)]
的短版本。后者通常用于在需要时将数组转换为切片。

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

旧答案:

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

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]
正确的方法(解决方案):

chars:=[]字符串{“a”、“a”、“b”}
对于i:=0;i/形成删除项索引以开始迭代下一项
}
}
格式打印F(“%+v”,字符)

来源:

检查一下为什么不看看语言规范
..
在这里有详细的解释吗?一方面,绝对正确(,每个人);另一方面,对于这些习语,对于移植蟒蛇等习语有很多不熟悉的地方,我不介意有一个解释让其他人去发现。参见
a[0:0]
不是
nil
,而是一个长度为0的片段<如果
a
nil
,则code>a[0:0]
将仅为
nil
。如果i是slice中的最后一个元素,您不会得到超出范围的异常吗
a=append(a[:i],a[i+1:]…)
@DaveC在我的项目中使用切片时,我确实会遇到该错误:/@Tyguy7,来自规范:“对于数组或字符串,如果为0,则索引在范围内。此操作的性能如何?我真的希望它不会在引擎盖下创建一个全新的切片。@Tyguy7我认为您试图删除循环中切片的元素。所以你必须小心索引。这很有趣,但并不是真正回答这个问题。这很好,但如果它可以删除数组中唯一的元素会更好。只是a向上看,尝试使用b中的第一个元素(替换为最后一个元素)如果您试图删除切片中的最后一个元素,则显然不起作用。这有助于解释为什么dave上的Mihai的答案为“否”,即使在提到第i个元素时,也指[i+1:]:
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)