Go语言 删除切片中的元素

htzpubme  于 2023-05-27  发布在  Go
关注(0)|答案(8)|浏览(175)
func main() {
    a := []string{"Hello1", "Hello2", "Hello3"}
    fmt.Println(a)
    // [Hello1 Hello2 Hello3]
    a = append(a[:0], a[1:]...)
    fmt.Println(a)
    // [Hello2 Hello3]
}

这个使用append函数的删除技巧是如何工作的?
看起来它在抓取第一个元素(空数组)之前的所有内容
然后在第一个元素(位置零)后追加所有内容
这是什么...(点点点点)做什么?

r1zhe5dt

r1zhe5dt1#

其中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

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

gijlo24d

gijlo24d2#

有两种选择:
A:您关心的是保持数组顺序:

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

von4xj4u

von4xj4u3#

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

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

qyuhtwio

qyuhtwio4#

...是可变参数的语法。
我认为它是由编译器使用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:]是“Hello2 Hello3”
这就是它的工作原理

js4nwp54

js4nwp545#

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

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

xj3cbfub

xj3cbfub6#

假设你的slice的值是这样的:[9 3 7 11 4 12 16 19 4]
删除7和11元素
x = append(x[:2], x[4:]...)
现在的结果是:
[9 4 12 16 19 4]
希望有帮助!

jdg4fx2g

jdg4fx2g7#

deletedIndex := 0
arr := []string{"0", "1", "2", "3", "4"}
before := arr[:deletedIndex]
after := arr[deletedIndex+1:]
data := append(before, after...)

创建两个没有删除值的切片并将它们连接起来

3qpi33ja

3qpi33ja8#

不是一个优雅的方法,但它的工作。(使用strings.Replace

var a = []string{"a", "b", "c", "d"}
    str := strings.Join(a, `,`)
    str2 := "a" // element to be removed

    arr := strings.Split(strings.Trim(strings.Replace(str, str2, "", -1), ","), ",")

相关问题