1

I am confused about how the following code works, especially what is the purpose of "..."

array = append(array[:i], array[i+1:]...)
blackgreen
  • 34,072
  • 23
  • 111
  • 129
Qi Zhang
  • 631
  • 1
  • 7
  • 15

4 Answers4

2

The line

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

creates a new slice by removing the item at position i in a, by combining the items from 0 to i (not included), and from i+1 to the end.

Your second question is what is the purpose of .... append accepts a slice as first argument, and an unlimited number of arguments, all with a type assignable to the type of its elements.

append is defined as

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

Writing

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

is equivalent as writing

a = append(a[:i], a[i+1], a[i+2], a[i+3], a[i+4]) //and so on, until the end of the slice.

Using a[i+1:]... is basically a shorthand syntax, as the Go spec describes in https://golang.org/ref/spec#Passing_arguments_to_..._parameters:

If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T. If f is invoked with no actual arguments for p, the value passed to p is nil. Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T

Playground

Flavio Copes
  • 4,131
  • 4
  • 27
  • 30
1
array = append(array[:i], array[i+1:]...)

is removing an element at index i

but another thing to point out is that slice is backed by an underlying array. For example:

package main

import (
    "fmt"
)

func main() {
    myArray := [6]int {1,2,3,4,5,6}

    mySlice := myArray[:]

    fmt.Println("myArray before append: ", myArray)

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

    fmt.Println("mySlice after append: ", mySlice)
    fmt.Println("myArray after append: ", myArray)
}

Result:

myArray before append:  [1 2 3 4 5 6]
mySlice after append:  [1 2 3 5 6]
myArray after append:  [1 2 3 5 6 6]

goplayground

In the underlying [1,2,3] stayed in place, that data never go moved anywhere, while [5,6] which were given by b[i+1] were appended to [1,2,3], and thus overwrote [3,4]; the other [6] stayed in place.

Even though you get different copy of a slice the underlying array will be the same*, this makes append a much more efficient operation then if the whole underlying array had to be copied over!

*If underlying array exceeds it's capacity, a new larger array will be allocated and values from old array would be copied to the new array, but this will never happen when removing an element.

Akavall
  • 82,592
  • 51
  • 207
  • 251
0

Built-in func append is Variadic Function.

To pass slice argument to any variadic function, you have to use ...

Go lang spec: Passing arguments to ... parameters

If f is variadic with final parameter type ...T, then within the function the argument is equivalent to a parameter of type []T. At each call of f, the argument passed to the final parameter is a new slice of type []T whose successive elements are the actual arguments, which all must be assignable to the type T. The length of the slice is therefore the number of arguments bound to the final parameter and may differ for each call site.


This line would give you a result value removing position i.

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

Let's say, we have

array := []int{1, 2, 3, 4, 5, 6, 7}
i := 3

fmt.Println("Original slice:", array)

part1 := array[:i]
part2 := array[i+1:]
fmt.Println("part1:", part1)
fmt.Println("part2:", part2)

array = append(array[:i], array[i+1:]...)
fmt.Println("Result slice:", array)

Output:

Original slice: [1 2 3 4 5 6 7]
part1: [1 2 3]
part2: [5 6 7]
Result slice: [1 2 3 5 6 7]

Play Link: https://play.golang.org/p/_cIk0VcD6w

jeevatkm
  • 4,571
  • 1
  • 23
  • 24
  • 1
    So what that line is doing is making a new slice by concatenating elements 0 through i-1 with elements starting with i+1 and continuing to the end of the slice. In other words, the effect is to delete element `i` from `array` (by making a new slice; it doesn't happen in place). – Andy Schweig Jul 20 '17 at 03:14
0

The purpose of ... is to save you typing individual elements as the append method takes first argument as slice and then variable number of arguments for elements to be appended.

i.e. You actually need to call append as

append(sliceName[:i], array[i+1], array[i+2], array[i+3], array[i+4])

but to avoid typing long list of elements, you can simply use ... after the slice or array to spread it as individual elements to be passed as arguments.

sahaj
  • 822
  • 5
  • 17