Removing an element from a slice duplicates the last element in Go? - 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.

Related

Why appending on slice modified another slice? [duplicate]

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]

Iterate a 2D slice of integers diagonally in go

What is an idiomatic way to iterate through a 2d slice of integers diagonally. Either the negative or positive diagonals?
Here is a playground with a 2d grid setup.
https://go.dev/play/p/Cpxg4a5HvrD
If x == y, or in this case, i == j, then it's the diagonal.
func main() {
size := 4
board := make([][]int, size)
for i := range board {
board[i] = append(board[i], make([]int, size)...)
}
for i, row := range board {
for j := range row {
board[i][j] = rand.Intn(9)
if i == j {
log.Println("diagonal:", board[i][j])
}
}
}
for _, row := range board {
fmt.Println(row)
}
}
That will print
2021/12/21 01:33:59 diagonal: 5
2021/12/21 01:33:59 diagonal: 6
2021/12/21 01:33:59 diagonal: 5
2021/12/21 01:33:59 diagonal: 8
[5 6 2 2]
[4 6 7 8]
[4 6 5 7]
[3 2 4 8]
If you want a different diagonal, you can offset one of the axis, for example x == y+1, or i == j+1
That will print
2021/12/21 01:38:07 diagonal: 4
2021/12/21 01:38:07 diagonal: 6
2021/12/21 01:38:07 diagonal: 4
[5 6 2 2]
[4 6 7 8]
[4 6 5 7]
[3 2 4 8]
For the inverse diagonals, need to use the len(board) - i, i.e.
for i, row := range board {
for j := range row {
board[i][j] = rand.Intn(9)
if len(board)-i == j {
log.Println("diagonal:", board[i][j])
}
}
}
Prints
2021/12/21 01:57:30 diagonal: 8
2021/12/21 01:57:30 diagonal: 5
2021/12/21 01:57:30 diagonal: 2
[5 6 2 2]
[4 6 7 8]
[4 6 5 7]
[3 2 4 8]

go slice not behaving as expected [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I was trying to get hands-on in slice and I observed that its not behaving as expected.
I was trying to get the cartesian product of n arrays of diff size. The output is not correct.
here is my code
func main() {
sl1 := []int{1,2,3}
sl2 := []int{4}
sl3 := []int{5,6}
sl4 := []int{8,9}
sl := [][]int{sl1,sl2,sl3,sl4}
res := cartesianMain(sl)
fmt.Println(res)
}
func cartesianMain(a [][]int) [][]int {
res := [][]int{}
for i:=0;i<len(a[0]) ;i++{
res = append(res,[]int{a[0][i]})
}
for i:= 1;i<len(a) ;i++{
res = cartesianProduct(res,a[i])
}
return res;
}
func cartesianProduct(a [][]int, b []int) [][]int {
result := [][]int{}
for _,v1 := range b {
for _,v2 := range a {
result = append(result, append(v2,v1))
}
}
return result
}
actual output:
[[1 4 5 9] [2 4 5 9] [3 4 5 9] [1 4 6 9] [2 4 6 9] [3 4 6 9] [1 4 5 9] [2 4 5 9] [3 4 5 9] [1 4 6 9] [2 4 6 9] [3 4 6 9]]
expected output:
if you see the sl4's 1st element 8 is over written by 9.
correct answer will be :
[[1 4 5 8] [2 4 5 8] [3 4 5 8] [1 4 6 8] [2 4 6 8] [3 4 6 8] [1 4 5 9] [2 4 5 9] [3 4 5 9] [1 4 6 9] [2 4 6 9] [3 4 6 9]]
This is becuase of how append works. In Go, slice is a header that keeps 3 property: Len, Cap, and Ptr. Len is the length of the slice it self, Cap is the capacity of the undrlying array of the slice (the memory), and Ptr is the pointer to the array.
When append appends to a slice where there are no more space in the underlying array, it allocates a new underlying array with some more space than needed and copies the content of the orignal slice into it and then adds the new element.
And When append appends to a slice where Cap > Len, i.e. where there are still sufficent space in the already allocated memory, append keeps the underlying array and copies the element to add to the a[Len+1] (where a is the underlying array). This will cause problem when two or more slice share the underlying memory.
A rule of thumb is to frequently check the need of copying a slice to avoid undesired sharing of underlying array.
To fix the problem, change result = append(result, append(v2,v1)) to result = append(result, append([]int{}, append(v2, v1)...)).
See also: https://blog.golang.org/slices
Note 1: append([]int{},append(v2,v1...)) is a shortcut of copy and apply. More tricks for slice can be found at: https://github.com/golang/go/wiki/SliceTricks .
Note 2: In Go, nil is a valid value for slice. so you can get rid of the seperation of split in cartesianMain by setting res to []int{nil}.
Note 3: For better performance and less allocations, it is a good practise to set the capacity (or length) for known slice. In cartesianProduct, you can use result := make([][]int, 0, len(a)*len(b)).
Playground: https://play.golang.org/p/rLqDGWoTLKS

re-slicing 2d slice in go

I came across a problem which needed editing several indexes of a 2-dimensional slice.
Imagine the following numbers as a 2-d slice of slices a [][]int
0 1 2 3
1 2 3 4
2 3 4 5
3 4 5 6
The problem is that I want to access and modify
0 1
1 2
As a sub-slice and I want a to be changed as well. I achieved that with this code :
sub := a[:2]
for i := range sub {
sub[i] = sub[i][:2]
}
Now fmt.Println(sub) prints [[0 1] [1 2]] But the problem is fmt.Println(a) is printing [[0 1] [1 2] [2 3 4 5] [3 4 5 6]]
The question is, how can I access this sub-slice without losing any data?
If your goal to modify the original []int slice elements when using sub, then copy the elements of a to a new slice. The code in the question modifies a directly.
sub := make([][]int, 2)
for i := range sub {
sub[i] = a[i][:2]
}
Just found a solution but don't know if it's the right way of doing so
sub := make([][]int, 2)
for i := range sub {
sub[i] = a[i][:2]
}
sub[0][0] = "876"
fmt.Println(a)
fmt.Println(sub)
now in the output I have
[[876 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6]]
[[876 1] [1 2]]

append to a new slice affect original slice

I have the following code which causes a weird result. I cannot understand why:
func main() {
var s = []int{2, 3}
var s1 = append(s, 4)
var a = append(s1, 5)
var b = append(s1, 6)
fmt.Println(s)
fmt.Println(s1)
fmt.Println(a)
fmt.Println(b)
}
This then results in:
[2 3]
[2 3 4]
[2 3 4 6]
[2 3 4 6]
My question is: why a is not [2 3 4 5] but [2 3 4 6]? I know append to b changes a, but how. Is this a bug because I never changed a directly and obviously I don't want this happen?
Keep in mind that a slice is a structure of 3 fields.
a pointer to the underlying array
length of the slice
capacity of the slice
append() function may either modify its argument in-place or return a copy of its argument with an additional entry, depending on the size and capacity of its input. append() function creates a new slice, if the length the slice is greater than the length of the array pointed by the slice.

Resources