How to prepend int to slice
Asked Answered
H

6

85

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.

Heretofore answered 12/12, 2018 at 6:43 Comment(0)
C
191

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.

Conceptionconceptual answered 12/12, 2018 at 6:58 Comment(3)
Any type of slice can be prepended using this. You have to use zero value for the first append() of the prependInt function. Eg for string - append(x, ""). Zero values for various types can are briefly described hereWyman
These tricks are good if you only need to prepend an item or two. But if you're prepending in a loop, it is significantly better to reverse the array, append what you need, and then reverse the array againDerrickderriey
For people using go 1.21 or newer, please see this answer for the std lib method slices.Insert()Prismatic
D
11

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

Dairying answered 2/12, 2020 at 12:3 Comment(4)
does this allocate ? or is there some trick in the compiler to improve it ?Ide
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.Ladylike
@mh-cbon Yes, this allocates. See prependInt in PeterSo's answer for a solution that minimizes allocations.Ladylike
FWIW, preventing a slice from being allocated seems like such a micro-optimization. There are very few real world scenarios where using some extra working space in memory to write simpler and more readable code isn't worth that trade off.Notecase
E
2

Pretty late to the party but I haven't seen a generic version, so here is mine:

func Prepend[T any](slice []T, elems ...T) []T {
    return append(elems, slice...)
}
Eclogite answered 1/11, 2023 at 16:43 Comment(0)
L
2

I'm also late, Google sent me here. With the introduction of the slices package in Go 1.21, you can use slices.Insert() to prepend to a slice:

s := []int{2, 3, 4, 5}
s = slices.Insert(s, 0, 1) //Inserts 1 at position 0 of the slice
fmt.Println(s)             //Will print [1 2 3 4 5]

Be careful as slices.Insert() will panic if out of range. More info on the docs: https://pkg.go.dev/slices#Insert

Lapidary answered 7/4 at 23:17 Comment(0)
O
-1

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

Overseas answered 22/4, 2021 at 3:35 Comment(1)
a = append([]int{10}, a...) is simpler than the append options shown here.Ladylike
S
-1

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:

Selsyn answered 12/4, 2022 at 7:47 Comment(1)
I downvoted because this seems overly complicated compared to append(elems, list...). It’s also a lot slower (~2.5x to 3x slower on large slices), and the append(results, 0) in the middle adds a superfluous 0 in the result.Nerte

© 2022 - 2024 — McMap. All rights reserved.