删除切片中的元素

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

Delete element in a slice

问题

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函数的删除技巧是如何工作的?

看起来它是先获取第一个元素之前的所有元素(空数组)

然后将第一个元素之后的所有元素(位置为零)追加上去

...(点点点)是什么作用?

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

How does this delete trick with the append function work?

It would seem that it's grabbing everything before the first element (empty array)

Then appending everything after the first element (position zero)

What does the ... (dot dot dot) do?

答案1

得分: 290

在这段代码中,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

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

英文:

Where a is the slice, and i is the index of the element you want to delete:

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

... is syntax for variadic arguments in Go.

Basically, when defining a function it puts all the arguments that you pass into one slice of that type. By doing that, you can pass as many arguments as you want (for example, fmt.Println can take as many arguments as you want).

Now, when calling a function, ... does the opposite: it unpacks a slice and passes them as separate arguments to a variadic function.

So what this line does:

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

is essentially:

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

Now, you may be wondering, why not just do

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

Well, the function definition of append is

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

So the first argument has to be a slice of the correct type, the second argument is the variadic, so we pass in an empty slice, and then unpack the rest of the slice to fill in the arguments.

答案2

得分: 45

有两种选择:

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

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

B:你不关心保留顺序(这可能更快):

a[i] = a[len(a)-1] // 用最后一个元素替换它。注意,只有在有足够元素的情况下才有效。
a = a[:len(a)-1]   // 去掉最后一个元素。

查看链接以了解如果你的数组是指针类型,可能会导致内存泄漏的影响。

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

英文:

There are two options:

A: You care about retaining array order:

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

B: You don't care about retaining order (this is probably faster):

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.

See the link to see implications re memory leaks if your array is of pointers.

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

答案3

得分: 13

不要回答我要翻译的问题。以下是要翻译的内容:

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

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

删除切片中的元素

英文:

Rather than thinking of the indices in the [a:]-, [:b]- and [a:b]-notations as element indices, think of them as the indices of the gaps around and between the elements, starting with gap indexed 0 before the element indexed as 0.

删除切片中的元素

Looking at just the blue numbers, it's much easier to see what is going on: [0:3] encloses everything, [3:3] is empty and [1:2] would yield {"B"}. Then [a:] is just the short version of [a:len(arrayOrSlice)], [:b] the short version of [0:b] and [:] the short version of [0:len(arrayOrSlice)]. The latter is commonly used to turn an array into a slice when needed.

答案4

得分: 5

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

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

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

当你在append中使用"elems"时,实际上它是一个切片([]type)。
所以"a = append(a[:0], a[1:]...)"的意思是"a = append(a[0:0], a[1:])"。

a[0:0]是一个空切片。

a[1:]是"Hello2 Hello3"。

这就是它的工作原理。

英文:

... is syntax for variadic arguments.

I think it is implemented by the complier using slice ([]Type), just like the function append :

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

when you use "elems" in "append", actually it is a slice([]type).
So "a = append(a[:0], a[1:]...)" means "a = append(a[0:0], a[1:])"

a[0:0] is a slice which has nothing

a[1:] is "Hello2 Hello3"

This is how it works

答案5

得分: 5

我正在使用接受的答案解决方案时遇到了索引超出范围的错误。

原因:
当范围开始时,它不是逐个迭代值,而是按索引迭代。
如果在范围内修改了切片,将会引发一些问题。

旧答案:

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
结果: [b]

实际结果:

// 实际结果
[a a b], 0, a
[a b], 1, b
[a b], 2, b
结果: [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-- // 从删除项索引开始迭代下一项
    }
}

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

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

英文:

I'm getting an index out of range error with the accepted answer solution.
Reason:
When range start, it is not iterate value one by one, it is iterate by index.
If you modified a slice while it is in range, it will induce some problem.

Old Answer:

chars := []string{&quot;a&quot;, &quot;a&quot;, &quot;b&quot;}

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

Expected :

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

Actual:

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

Correct Way (Solution):

chars := []string{&quot;a&quot;, &quot;a&quot;, &quot;b&quot;}

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

fmt.Printf(&quot;%+v&quot;, chars)

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

答案6

得分: 0

假设你的切片的值是这样的:
[9 3 7 11 4 12 16 19 4]

要删除第7和第11个元素,可以使用以下代码:
x = append(x[:2], x[4:]...)

现在的结果是:
[9 4 12 16 19 4]

希望对你有帮助!

英文:

assuming the value of your slice is this:
[9 3 7 11 4 12 16 19 4]

to delete the 7 and 11 element

x = append(x[:2], x[4:]...)

the result is now:

[9 4 12 16 19 4]

hope that helps!

答案7

得分: 0

删除索引 := 0
arr := []string{"0", "1", "2", "3", "4"}
之前 := arr[:删除索引]
之后 := arr[删除索引+1:]
数据 := append(之前, 之后...)

创建两个不包含删除值的切片,并将它们连接起来。

英文:
deletedIndex := 0
arr := []string{&quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;}
before := arr[:deletedIndex]
after := arr[deletedIndex+1:]
data := append(before, after...)

Create two slices without deleted value and concat them

答案8

得分: -1

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

    var a = []string{"a", "b", "c", "d"}
	str := strings.Join(a, ",")
	str2 := "a" // 要移除的元素

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

Not an elegant approach but it works. (Using strings.Replace)

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

	arr := strings.Split(strings.Trim(strings.Replace(str, str2, &quot;&quot;, -1), &quot;,&quot;), &quot;,&quot;)

huangapple
  • 本文由 发表于 2014年7月30日 05:36:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/25025409.html
匿名

发表评论

匿名网友

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

确定