Insert a value in a slice at a given index

A simple append is what you need:

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

Note: len(a) > 0 && index < len(a)

Should len(a) == index, meaning nil or empty slice or append after the last element:

a = append(a, value)

Inserting at the index zero for slice of ints:

a = append([]int{value}, a...)

All in one function:

// 0 <= index <= len(a)
func insert(a []int, index int, value int) []int {
    if len(a) == index { // nil or empty slice or after last element
        return append(a, value)
    }
    a = append(a[:index+1], a[index:]...) // index < len(a)
    a[index] = value
    return a
}

Usage:

    a := []int{10, 30, 40}
    a = insert(a, 1, 20)
    fmt.Println(a) // [10 20 30 40]

And for the OP:

    slice1 := []int{1, 3, 4, 5}
    slice2 := []int{2, 4, 6, 8}
    // slice1 = insert(slice1, 1, slice2[2])
    slice1 = append(slice1[:2], slice1[1:]...)
    slice1[1] = slice2[2]

    fmt.Println(slice1) // [1 6 3 4 5]

Benchmark:

go version
# go version go1.16.3 linux/amd64
make bench
go test -benchmem -bench . -args -n 32
# BenchmarkInsert-8      4125085  275.0 ns/op  512 B/op  1 allocs/op
# BenchmarkInsert2-8     3778551  316.0 ns/op  512 B/op  1 allocs/op

go test -benchmem -bench . -args -n 1000
# BenchmarkInsert-8       198364  5876 ns/op  16384 B/op  1 allocs/op
# BenchmarkInsert2-8      205197  7123 ns/op  16384 B/op  1 allocs/op

go test -benchmem -bench . -args -n 1000000
# BenchmarkInsert-8          643  1898436 ns/op 10002437 B/op  1 allocs/op
# BenchmarkInsert2-8         368  3248385 ns/op 10002436 B/op  1 allocs/op

Code:

func insert(a []int, index int, value int) []int {
    a = append(a[:index+1], a[index:]...) // Step 1+2
    a[index] = value                      // Step 3
    return a
}
func insert2(a []int, index int, value int) []int {
    last := len(a) - 1
    a = append(a, a[last])           // Step 1
    copy(a[index+1:], a[index:last]) // Step 2
    a[index] = value                 // Step 3
    return a
}
func BenchmarkInsert(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = insert(a, 2, 42)
    }
}
func BenchmarkInsert2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = insert2(a, 2, 42)
    }
}

var (
    n    = flag.Int("n", 32, "buffer length")
    a, r []int
)

// We use TestMain to set up the buffer.
func TestMain(m *testing.M) {
    flag.Parse()
    a = make([]int, *n)
    os.Exit(m.Run())
}

You may combine the two first steps to one; by using:

    a = append(a[:index+1], a[index:]...)
  1. This makes sure the array has enough capacity to accommodate the new element.
  2. This copies all required elements to one index higher to make room for the new element.
  3. Set the element at the index, using a single assignment: a[index] = value

Which is more efficient, according to the benchmarks.


Should you need to insert at index > cap(a) (note: untested code) – try it on the The Go Playground:

package main

import "fmt"

func insert(a []int, index int, value int) []int {
    n := len(a)
    if index < 0 {
        index = (index%n + n) % n
    }
    switch {
    case index == n: // nil or empty slice or after last element
        return append(a, value)

    case index < n: // index < len(a)
        a = append(a[:index+1], a[index:]...)
        a[index] = value
        return a

    case index < cap(a): // index > len(a)
        a = a[:index+1]
        for i := n; i < index; i++ {
            a[i] = 0
        }
        a[index] = value
        return a

    default:
        b := make([]int, index+1) // malloc
        if n > 0 {
            copy(b, a)
        }
        b[index] = value
        return b
    }
}

func main() {
    a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    a = a[:5]
    fmt.Println(insert(a, 7, 70)) // [0 1 2 3 4 0 0 70]

    a = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    a = a[:4]
    fmt.Println(insert(a, 5, 50)) // [0 1 2 3 0 50]

    fmt.Println(insert(make([]int, 0, 50), 10, 10)) // [0 0 0 0 0 0 0 0 0 0 10]

    fmt.Println(insert([]int{1}, -1, 10))       // [10 1]
    fmt.Println(insert([]int{1, 2, 3}, -2, 10)) // [1 10 2 3]
    fmt.Println(insert([]int{1, 2, 3}, -1, 10)) // [1 2 10 3]
    fmt.Println(insert([]int{1, 2, 3}, -4, 10)) // [1 2 10 3]

    fmt.Println(insert(nil, 0, 0))       // [0]
    fmt.Println(insert([]int{}, 0, 0))   // [0]
    fmt.Println(insert([]int{1}, 1, 10)) // [1 10]

    fmt.Println(insert(nil, 5, 50)) // [0 0 0 0 0 50]

    fmt.Println(insert(make([]int, 0, 1), 1, 10)) // [0 10]
    fmt.Println(insert(make([]int, 0, 1), 2, 20)) // [0 0 20]
    fmt.Println(insert(make([]int, 0, 1), 3, 30)) // [0 0 0 30]

    fmt.Println(insert([]int{0, 10, 20, 30}, 5, 50)) // [0 10 20 30 0 50]
    fmt.Println(insert([]int{0}, 5, 50))             // [0 0 0 0 0 50]
    fmt.Println(insert([]int{0, 10}, 0, 0))          // [0 0 10]
    fmt.Println(insert([]int{0, 10}, 1, 5))          // [0 5 10]
    fmt.Println(insert(make([]int, 5, 50), 0, 0))    // [0 0 0 0 0 0]
}

Using generics (note: untested code) – try it on the The Go Playground:

package main

import "fmt"

func insert[T any](a []T, index int, value T) []T {
    n := len(a)
    if index < 0 {
        index = (index%n + n) % n
    }
    switch {
    case index == n: // nil or empty slice or after last element
        return append(a, value)

    case index < n: // index < len(a)
        a = append(a[:index+1], a[index:]...)
        a[index] = value
        return a

    case index < cap(a): // index > len(a)
        a = a[:index+1]
        var zero T
        for i := n; i < index; i++ {
            a[i] = zero
        }
        a[index] = value
        return a

    default:
        b := make([]T, index+1) // malloc
        if n > 0 {
            copy(b, a)
        }
        b[index] = value
        return b
    }
}

func main() {
    a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    a = a[:5]
    fmt.Println(insert(a, 7, 70)) // [0 1 2 3 4 0 0 70]

    a = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    a = a[:4]
    fmt.Println(insert(a, 5, 50)) // [0 1 2 3 0 50]

    fmt.Println(insert(make([]int, 0, 50), 10, 10)) // [0 0 0 0 0 0 0 0 0 0 10]

    fmt.Println(insert([]int{1}, -1, 10))       // [10 1]
    fmt.Println(insert([]int{1, 2, 3}, -2, 10)) // [1 10 2 3]
    fmt.Println(insert([]int{1, 2, 3}, -1, 10)) // [1 2 10 3]
    fmt.Println(insert([]int{1, 2, 3}, -4, 10)) // [1 2 10 3]

    fmt.Println(insert(nil, 0, 0))       // [0]
    fmt.Println(insert([]int{}, 0, 0))   // [0]
    fmt.Println(insert([]int{1}, 1, 10)) // [1 10]

    fmt.Println(insert(nil, 5, 50)) // [0 0 0 0 0 50]

    fmt.Println(insert(make([]int, 0, 1), 1, 10)) // [0 10]
    fmt.Println(insert(make([]int, 0, 1), 2, 20)) // [0 0 20]
    fmt.Println(insert(make([]int, 0, 1), 3, 30)) // [0 0 0 30]

    fmt.Println(insert([]int{0, 10, 20, 30}, 5, 50)) // [0 10 20 30 0 50]
    fmt.Println(insert([]int{0}, 5, 50))             // [0 0 0 0 0 50]
    fmt.Println(insert([]int{0, 10}, 0, 0))          // [0 0 10]
    fmt.Println(insert([]int{0, 10}, 1, 5))          // [0 5 10]
    fmt.Println(insert(make([]int, 5, 50), 0, 0))    // [0 0 0 0 0 0]
}

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)