ChatGPT解决这个技术问题 Extra ChatGPT

How to prepend int to slice

I am fairly new to Go and thus my question might seem a bit naive.

I have a slice which I created using

var x []int;
for i := 2; i < 10; i += 2 {
    x = append(x, i);
}

I want to prepend an integer to this slice, something like

x = append(2, x)

but obviously it won't work since append needs a slice as the first argument.

I have tried this but it only works for strings and it's not working in my case.

Append and reverse?
You should make the first parameter to array which you want to prepend(push).

Z
Zombo

Use a slice composite literal: []int{1}, For example:

package main

import (
    "fmt"
)

func main() {
    var x []int
    for i := 2; i < 10; i += 2 {
        x = append(x, i)
    }
    fmt.Println(x)

    x = append([]int{1}, x...)

    fmt.Println(x)
}

Playground: https://play.golang.org/p/Yc87gO7gJlD

Output:

[2 4 6 8]
[1 2 4 6 8]

However, this more efficient version may make fewer allocations, An allocation is only necessary when there is no spare slice capacity.

package main

import (
    "fmt"
)

func main() {
    var x []int
    for i := 2; i < 10; i += 2 {
        x = append(x, i)
    }
    fmt.Println(x)

    x = append(x, 0)
    copy(x[1:], x)
    x[0] = 1

    fmt.Println(x)
}

Playground: https://play.golang.org/p/fswXul_YfvD

Output:

[2 4 6 8]
[1 2 4 6 8]

Good code must be readable. In Go, we often hide implementaion details inside a function. Go compilers are optimizing compilers, small, simple functions (like prependInt) are inlined.

package main

import (
    "fmt"
)

func prependInt(x []int, y int) []int {
    x = append(x, 0)
    copy(x[1:], x)
    x[0] = y
    return x
}

func main() {
    var x []int
    for i := 2; i < 10; i += 2 {
        x = append(x, i)
    }
    fmt.Println(len(x), cap(x), x)

    x = prependInt(x, 1)

    fmt.Println(len(x), cap(x), x)
}

Playground: https://play.golang.org/p/wl6gvoXraKH

Output:

4 4 [2 4 6 8]
5 8 [1 2 4 6 8]

See Go SliceTricks.


s
sanchezcl

The current version is go1.14.11

Prepend without a for loop:

package main

import "fmt"
func main () {
  data := []int{1, 2, 3, 4}
  fmt.Println(data)
  data = append([]int{99}, data...)
  fmt.Println(data)
}

Example taken form: https://codingair.wordpress.com/2014/07/18/go-appendprepend-item-into-slice/

Works with integers: https://play.golang.org/p/gaLhB5_d1Iu


does this allocate ? or is there some trick in the compiler to improve it ?
The prepend operation shown here is identical to the accepted answer. The difference between this answer and the accepted answer is that the example data is created with a composite literal instead of a for loop.
@mh-cbon Yes, this allocates. See prependInt in PeterSo's answer for a solution that minimizes allocations.
s
stephanve

I know the Question is only for int but thought I'd add this to the discussion:

https://play.golang.com/p/PNax2a1rL3q

import (
    "golang.org/x/exp/constraints"
)

type Number interface {
    constraints.Signed | constraints.Unsigned | constraints.Float
}

func prepend[T Number](list []T, elems ...T) []T {
    results := make([]T, len(list)+len(elems))
    results = append(results, 0)
    copy(results[len(elems):], list)
    copy(results[:len(elems)], elems)
    return results
}

References:

How to write a generic function that accepts any numerical type?

https://pkg.go.dev/golang.org/x/exp/constraints


Z
Zombo

Another answer uses append and copy, but you can do it with just append, in one or two lines:

package main
import "fmt"

func main() {
   {
      a := []int{20, 30}
      a = append(append(a, 10), a...)[len(a):]
      fmt.Println(a)
   }
   {
      a := []int{20, 30}
      a = append(make([]int, 1), a...)
      a[0] = 10
      fmt.Println(a)
   }
   { // if starting with empty slice, use: a := make([]int, 0, 1)
      a := []int{20, 30}
      a = append(a[:1], a...)
      a[0] = 10
      fmt.Println(a)
   }
}

Or as another option, you can use linked list:

package main

import (
   "container/list"
   "fmt"
)

func main() {
   a := list.New()
   a.PushBack(20)
   a.PushBack(30)
   a.PushFront(10)
   for n := a.Front(); n != nil; n = n.Next() {
      fmt.Println(n.Value)
   }
}

https://golang.org/pkg/container/list


a = append([]int{10}, a...) is simpler than the append options shown here.