Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert a value in a slice at a given index

Tags:

slice

go

Given

array1 := []int{1, 3, 4, 5} array2 := []int{2, 4, 6, 8} 

I want to insert array2[2] i.e 6 at array1[1] i.e before 3 so that array1 becomes a slice of {1, 6, 3, 4, 5}. How can I do it?

Most the techniques I read online involve using the : operator but results in remaining elements being inserted as well. How can I append single values at an index in a slice?

like image 875
chefcurry7 Avatar asked Sep 09 '17 06:09

chefcurry7


People also ask

How do you add an element to a slice?

To add an element to a slice , you can use Golang's built-in append method. append adds elements from the end of the slice. The first parameter to the append method is a slice of type T . Any additional parameters are taken as the values to add to the given slice .

How do I insert a value slice in Golang?

Inserting into slice Golang doesn't support any built-in functions to add items into a slice. To do this, we have to manually implement the insert() method using the append() function.

How do you add an element to an array in go?

Let's say that we want to insert an element in an array at position 2. First we need space (length) in order to insert a new element. Appending an element, will make a new space at the end. Then we are able to shift a block of elements from position 2 until the end.

How to insert an item at a specific index in JavaScript?

This post will discuss how to insert an item at a specific index in an array using JavaScript. 1. Using Array.prototype.splice () function The splice () method can be used to modify the array by removing or replacing existing elements and/or adding new elements in-place.

How to use the slice () method in Python?

The slice () method is used to return an array between two indices. It takes two parameters, one is the beginning index which specifies and the other is the ending index. The first part of the string is extracted using the starting position as 0 and the ending position as the index where the new string has to be inserted.

How to slice an element in a struct?

Set the element at the proper index, using a single assignment. Note that in some special cases (when the slice element is big, like a big struct), it may be faster to append the last element, and then it's enough to copy 1 less elements (because the appended last element is right where it needs to be). This will result in the same slice.

How to set the index of an element in a struct?

Set the element at the proper index, using a single assignment. Note that in some special cases (when the slice element is big, like a big struct), it may be faster to append the last element, and then it's enough to copy 1 less elements (because the appended last element is right where it needs to be).


2 Answers

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.

like image 155
wasmup Avatar answered Sep 25 '22 19:09

wasmup


Simple, efficient and logical way:

  1. Make sure array1 has enough capacity (length) to accomodate the new, insertable element. To do that, append a single element using the builting append() (doesn't matter what that is, it'll get overwritten).
  2. To insert an element, existing elements must be shifted (copied over to 1 index higher) to make room for that element, e.g. using the builtin copy() (elements you want to insert before).
  3. Set the element at the proper index, using a single assignment.

In code:

array1 := []int{1, 3, 4, 5} array2 := []int{2, 4, 6, 8}  array1 = append(array1, 0)   // Step 1 copy(array1[2:], array1[1:]) // Step 2 array1[1] = array2[2]        // Step 3  fmt.Println(array1) 

Output (try it on the Go Playground):

[1 6 3 4 5] 

Optimization in special cases

Note that in some special cases (when the slice element is big, like a big struct), it may be faster to append the last element, and then it's enough to copy 1 less elements (because the appended last element is right where it needs to be).

This is how it looks like:

last := len(array1) - 1 array1 = append(array1, array1[last]) // Step 1 copy(array1[2:], array1[1:last])      // Step 2 array1[1] = array2[2]                 // Step 3 

This will result in the same slice. Try this one on the Go Playground.

like image 26
icza Avatar answered Sep 22 '22 19:09

icza