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 int
s:
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:]...)
- This makes sure the array has enough capacity to accommodate the new element.
- This copies all required elements to one index higher to make room for the new element.
- 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]
}