Why appending on slice modified another slice? [duplicate] - go

This question already has answers here:
Why does append() modify the provided slice? (See example)
(1 answer)
Golang append changing append parameter [duplicate]
(2 answers)
Why does append modify passed slice
(5 answers)
Deleting element of slice modifies original value [duplicate]
(1 answer)
Closed last year.
package main
import "fmt"
func main() {
src := []int{0, 1, 2, 3, 4, 5, 6}
a := src[:3]
b := src[3:]
a = append(a, 9)
fmt.Println(a, b)
}
output:
[0 1 2 9] [9 4 5 6]
Did append modified the underlay array as []int{0, 1, 2, 9, 4, 5, 6}?
Slice a was copied as a new slice with a new underlay array with value [0, 1, 2, 9] and slice b still pointing to the old array that was modified.
Thanks for any hints, much appreciated

Slice a was copied as a new slice with a new underlay array with value [0, 1, 2, 9] and slice b still pointing to the old array that was modified.
a := src[:3] created a slice (a pointer to the src head, length=3, capacity=7)
b := src[3:] created a slice(a pointer to the src[3],length=4, capacity=4)
a and b shares the same memory created by src
a = append(a, 9),when appending to the same slice, as long as it does not exceed cap, it is the same array that is modified
Did append modified the underlay array as []int{0, 1, 2, 9, 4, 5, 6}
YES
If the append exceed the cap of a, new array will be allocated and data will be copied the the new array
try this out:
package main
import "fmt"
func main() {
src := []int{0, 1, 2, 3, 4, 5, 6}
a := src[:3]
b := src[3:]
a = append(a, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9)
fmt.Println(a, b)
}
Output:
[0 1 2 9 9 9 9 9 9 9 9 9 9] [3 4 5 6]

Related

Removing an element from a slice duplicates the last element in Go?

I was playing with slices in go to better understand the behaviour.
I wrote the following code:
func main() {
// Initialize
myslice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
newSlice := myslice
fmt.Println(myslice)
fmt.Println(newSlice)
removeIndex := 3
newSlice = append(newSlice[:removeIndex], newSlice[removeIndex+1:]...)
fmt.Println(myslice)
fmt.Println(newSlice)
}
This is the output:
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]
[1 2 3 5 6 7 8 9 9]
[1 2 3 5 6 7 8 9]
I dont really understand what happens with newSlice that duplicates the 9 at the end. Also, does this mean, that this operation removes the given element from the underlying array?
https://go.dev/play/p/pf7jKw9YcfL
The append operation simply shifts the elements of the underlying array. newSlice and mySlice are two slices with the same underlying array. The only difference is the length of the two: After append, newSlice has 8 elements, and mySlice still has 9 elements.

The most concise way to concatenate 3 or more slices

I am looking for a way to concisely and efficiently concatenate 3 or more slices in Go.
Let's say I want to concatenate the following slices (all the code can be found here - https://play.golang.org/p/6682YiFF8qG):
a := []int{1, 2, 3}
b := []int{4, 5, 6}
c := []int{7, 8, 9}
My first attempt is by using the append method:
d1 := append(a, b...)
d1 = append(d1, c...) // [1 2 3 4 5 6 7 8 9]
However, this method is verbose and requires 2 append calls for concatenating three slices. So, for n slices, I will need n-1 calls to append, which is not only verbose, but also inefficient as it requires multiple allocations.
My next attempt is to create a variadic function to handle the concatenation with only one new slice allocation:
func concat(slicesOfSlices ...[]int) []int {
var totalLengthOfSlices int
for _, slice := range slicesOfSlices {
totalLengthOfSlices += len(slice)
}
arr := make([]int, 0, totalLengthOfSlices)
for _, slice := range slicesOfSlices {
arr = append(arr, slice...)
}
return arr
}
Then I can use it as follows:
d2 := concat(a, b, c) // [1 2 3 4 5 6 7 8 9]
To illustrate, I want to emulate the following convenient functionality of the spread operator in JavaScript, which I often use in the following way:
const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [7, 8, 9];
const d = [...a, ...b, ...c]; // [1, 2, 3, 4, 5, 6, 7, 8, 9]
In other words, I am looking for a way to do something like d3 := append(a, b, c) or d3 := append(a, b..., c...) but with the standard Go library or using less code than I did.
Note on possible duplicates
I don't think this is a duplicate of the question "How to concatenate two slices" as my question is about concatenating 3 or more slices in the most concise and idiomatic way.
You could use your first method of using append like this:
a := []int{1, 2, 3, 4}
b := []int{9, 8, 7, 6}
c := []int{5, 4, 3, 2}
a = append(a, append(b, c...)...)
That being said, I think that your variadic concat function is cleaner and isn't very much code for a utility function.
(Go Playground Link)
Good luck!

Golang - How to remove a row from a matrix?

So I have this 2D slice, for example:
s := [][]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
}
fmt.Println(s)
//Outputs: [[0 1 2 3] [4 5 6 7] [8 9 10 11]]
How can I remove a full row from this 2D slice, so that the result would look like this if I decide to remove the middle row:
[[0 1 2 3] [8 9 10 11]]
The formula to delete row at index i is:
s = append(s[:i], s[i+1:])
Here's a working example:
package main
import (
"fmt"
)
func main() {
s := [][]int{
{0, 1, 2, 3},
{4, 5, 6, 7}, // This will be removed.
{8, 9, 10, 11},
}
// Delete row at index 1 without modifying original slice by
// appending to a new slice.
s2 := append([][]int{}, append(s[:1], s[2:]...)...)
fmt.Println(s2)
// Delete row at index 1. Original slice is modified.
s = append(s[:1], s[2:]...)
fmt.Println(s)
}
Try it in the Go playground.
I recommend you to read Go Slice Tricks. Some of the tricks can be applied to multidimensional slices as well.
You can try the following:
i := 1
s = append(s[:i],s[i+1:]...)
You can try the working code in the Golang playground
Another alternative way is to use the following:
i := 1
s = s[:i+copy(s[i:], s[i+1:])]
Golang Playground

Concatenate 2 slices in golang

I have 2 slices,
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{3, 4, 5, 6, 7}
I want the resultant
s3 = []int{1, 2, 3, 4, 5, 3, 4, 5, 6, 7}
I am doing something like:
for _, x := range s1 {
s2 = append(s2, x)
}
This looks very trivial question but trust me I don't find a one line solution to this.
How can we go about this?
This is what the builtin append() function is for: to append values (which may be values of a slice) to the end of another. And the result is the concatenation.
If you want s3 to be "independent" of s1 and s2, then append s1 to an empty or nil slice, then append s2 to the result:
s3 := append(append([]int{}, s1...), s2...)
fmt.Println(s3)
If s3 may use / overlap s1, you can simply append s2 to s1:
s4 := append(s1, s2...)
fmt.Println(s4)
Output in both cases (try it on the Go Playground):
[1 2 3 4 5 3 4 5 6 7]
Note: What this "overlapping" means is that if you append values to s1, if it has enough capacity, no new slice will be allocated, s1 will be resliced to have enough length to accommodate the elements you want to append to it. This may have surprising side-effects if used unwisely, like in this example:
arr := [...]int{1, 2, 3, 4, 5, 6, 7, 0, 0, 0}
s1 := arr[:5]
s2 := arr[2:7]
fmt.Println("s1:", s1, "cap:", cap(s1))
fmt.Println("s2:", s2)
s3 := append(s1, s2...)
fmt.Println("s3:", s3)
fmt.Println("s2:", s2)
Output is (try it on the Go Playground):
s1: [1 2 3 4 5] cap: 10
s2: [3 4 5 6 7]
s3: [1 2 3 4 5 3 4 5 6 7]
s2: [3 4 5 3 4]
What may be surprising here is that when we appended s2 to s1 and stored the result in s3 (which is what we expected), contents (elements) of s2 also changed. The reason for this is that append() saw that s1 has enough capacity to append s2 to it (elements of s2), so it did not create a new array, it just resliced s1 and added elements "in-place". But the area where the additional elements were written is the exact same memory where elements of s2 reside, so elements of s2 also got overwritten.
I would recommend you to give a look at this page: https://github.com/golang/go/wiki/SliceTricks
It's an official documentation by golang for slices. For your problem you just need to use append :)

How to separate numbers from a slice?

Let's say I have a list with 10 numbers:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I would like my program to slice every 3 numbers, for example:
[1,2,3]
[4,5,6]
[7,8,9]
How can I do it?
Grateful
For example, with n = 3,
package main
import "fmt"
func main() {
list := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for a, n := list, 3; len(a) >= n; a = a[n:] {
slice := a[:n]
fmt.Println(slice)
}
}
Output:
[1 2 3]
[4 5 6]
[7 8 9]
you could make a something like this (sorry for pseudo code)
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
while (array){
list = ""
for($i=1;$i -le 3;$i++){
list.add = array[$i]
remove from array the array[$i]
}
your list now here (list)
}
you could ask the first 3 values and after that you remove it

Resources