Iterate a 2D slice of integers diagonally in go - 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]

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.

Value has been changed in method

I'm solving a problem in leetcode using recursion.
But, the value which is used as a parameter is changed in the method.
package main
import "fmt"
func makeCmbs(cmbs [][]int, nums []int, remains []int, k int) [][]int {
fmt.Println("==", cmbs, nums, remains, k) // (2)
if k == 0 {
cmbs = append(cmbs, nums)
fmt.Println("!", nums, cmbs)
return cmbs
}
for i, num := range remains {
fmt.Printf("-[%d] num:%d cmbs:%v remains:%v\n", i, num, cmbs, remains) // (1) cmbs here is [[1,2,3,4]]
cmbs = makeCmbs(cmbs, append(nums, num), remains[i+1:], k-1) // cmbs in makeCmbs method is [[1,2,3,5]] ???
fmt.Printf("+[%d] num:%d cmbs:%v\n", i, num, cmbs)
}
return cmbs
}
func combine(n int, k int) [][]int {
remains := make([]int, n)
for i := 0; i < n; i++ {
remains[i] = i + 1
}
return makeCmbs([][]int{}, []int{}, remains, k)
}
func main() {
combine(5, 4)
}
Bellow is its beginning of output.
== [] [] [1 2 3 4 5] 4
-[0] num:1 cmbs:[] remains:[1 2 3 4 5]
== [] [1] [2 3 4 5] 3
-[0] num:2 cmbs:[] remains:[2 3 4 5]
== [] [1 2] [3 4 5] 2
-[0] num:3 cmbs:[] remains:[3 4 5]
== [] [1 2 3] [4 5] 1
-[0] num:4 cmbs:[] remains:[4 5]
== [] [1 2 3 4] [5] 0
! [1 2 3 4] [[1 2 3 4]]
+[0] num:4 cmbs:[[1 2 3 4]]
-[1] num:5 cmbs:[[1 2 3 4]] remains:[4 5] <---- cmbs is [[1 2 3 4]]
== [[1 2 3 5]] [1 2 3 5] [] 0 <---- why [[1 2 3 5]] ???
As you can see those last two lines, cmbs [[1 2 3 4]] became [[1 2 3 5]].
Could anybody please give me a clue why cmbs value is changed in makeCmbs method?
Let start with recursion last recursive loop of calling makeCmbs
cmbs = makeCmbs(cmbs, append(nums, num), remains[i+1:], k-1)
As remains[i+1:] where the value of i at last loop will be the highest i.e
i = len(remains-1)
So it means it means i+1 is two (2) greater then len(remains-1) that is why remain[i+1] will be empty array ([]) for first two last recusrive rounds.
This is how it works. I hope I made it to the imaginative height of this problem.
UPDATE:
For the first time when k=0
start of function: num:[1 2 3 4] cmbs:[] remains:[5], k:0
So if k=0 condition is true
if k == 0 {
cmbs = append(cmbs, nums)
fmt.Printf("in side if: num:%d cmbs:%v k:%v\n", nums, cmbs, k)
return cmbs
}
that is the first return of recursion
as cmbs = [] and nums = [1 2 3 4]
cmbs = append(cmbs, nums)
Now retuned value is cmb from if condition is [[1 2 3 4]] to the for loop this line
cmbs = makeCmbs(cmbs, append(nums, num), remains[i+1:], k-1)
and here loop ends so it also return the same
[[1 2 3 4]]
But at before that recursion nums was append of nums+num that is [1 2 3 5] so that is why when it return back in the second last recursion at the same for loop call cmbs hold [1 2 3 5].
It is indeed a difficult question to image but can be solved easily with a debugger.

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]]

Confused about the depth-first-search result when using Golang

I tried to solve the 'Combination Sum' on leetcode, and the result is wrong when using test case:
[7,3,2] 18
I used C++ with the same logic and passed, but when using Golang, my result is:
[[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,7,3,3],[2,2,2,2,3,7],[2,2,2,3,3,3,3],[2,2,7,7],[2,3,3,3,7],[3,3,3,3,3,3]]
and the correct one should be
[[2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,3,3],[2,2,2,2,3,7],[2,2,2,3,3,3,3],[2,2,7,7],[2,3,3,3,7],[3,3,3,3,3,3]]
the code is shown below:
import "sort"
func combinationSum(candidates []int, target int) [][]int {
result := make([][]int, 0, 0)
resultp := &result
sort.Ints(candidates)
helper(candidates, 0, target, make([]int, 0, 0), resultp, len(candidates))
return *resultp
}
func helper(nums []int, index int, target int, list []int, resultp *[][]int, length int) {
if target == 0 {
*resultp = append(*resultp, list)
return
}
for i := index; i < length; i++ {
if i != index && nums[i] == nums[i - 1] {
continue
}
if (nums[i] > target) {
break
}
helper(nums, i, target - nums[i], append(list, nums[i]), resultp, length)
}
}
Can anyone tell me why the result is incorrect, I am just confused about the [2,2,2,2,2,7,3,3] in my answer, why the 7 is before the 3 since the array has been sorted? Or anyone can tell me what mistake I have made in my code
append function may or may not modify the underlying array that your slice refers to. So you are not creating a completely new list when using append. I changed helper to match your desired behavior.
for i := index; i < length; i++ {
if i != index && nums[i] == nums[i - 1] {
continue
}
if nums[i] > target {
break
}
var newList []int
newList = append(newList, list...)
newList = append(newList, nums[i])
helper(nums, i, target - nums[i], newList, resultp, length)
}
If list has capacity, then it will be modified and therefore you are modifying your argument. Instead make a copy of list, and then append nums[i] to it.
See Go Slices: usage and internals
The line
helper(nums, i, target - nums[i], append(list, nums[i]), resultp, length)
may not perform as expected. It is called within the loop, and you are probably assuming that in the each iteration the append will always add the new member to the existing slice. If has more complex behavior that you seem not caring about enough:
If the new value fits into the current capacity of the backing array withing the slice, it is added to the current backing array. All variables assigned to that slice now report the updated content with the added new value present.
If the value does not fit, a new array is allocated. In this case further modifications of the returned slice will not change the content of the initial slice if that old value is also retained.
I am under impression that you may not expect value/content disagreement between the value returned by append and the parameter list you pass to it.
This behavior is described here (scroll to "gotcha").
So you can see the behavior a bit better by adding some print output:
https://play.golang.org/p/JPmqoAJE4S
Importantly, you can see it at this point:
0694 helper [2 3 7] 1 1 [2 2 2 2 2 2 2 3] [[2 2 2 2 2 2 2 2 2]] 3
4425 calling down 1 6 [2 2 2 2 2 2] 3
8511 helper [2 3 7] 1 3 [2 2 2 2 2 2 3] [[2 2 2 2 2 2 2 2 2]] 3
8511 calling down 1 3 [2 2 2 2 2 2 3] 3
8162 helper [2 3 7] 1 0 [2 2 2 2 2 2 3 3] [[2 2 2 2 2 2 2 2 2]] 3
8162 solution [2 2 2 2 2 2 3 3] [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 3 3]]
1318 calling down 1 8 [2 2 2 2 2] 3
5089 helper [2 3 7] 1 5 [2 2 2 2 2 3] [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 3 3 3]] 3
5089 calling down 1 5 [2 2 2 2 2 3] 3
4728 helper [2 3 7] 1 2 [2 2 2 2 2 3 3] [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 3 3 3]] 3
1318 calling down 2 8 [2 2 2 2 2] 7
3274 helper [2 3 7] 2 1 [2 2 2 2 2 7] [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 7 3 3]] 3
This is the sequence of actions:
You recursively call with [2 2 2 2 2 2 3] and append 3. You find that this is a valid solution and add [2 2 2 2 2 2 3 3] to the result slice.
You return up a few levels until you're back to [2 2 2 2 2] (before adding the 6th 2) and start trying to add 3s. You recursively call with [2 2 2 2 2] and append 3. Unfortunately, this overwrites your existing solution [2 2 2 2 2 2 3 3]. Since it's using the same backing array, you append 3 to the first 5 items in that slice, overwriting the 6th index in the slice you previously added to your solution set. Your second solution becomes [2 2 2 2 2 3 3 3] (note the 3 in the 6th slot)
You find that this solution set isn't going to work after a couple iterations (at [2 2 2 2 2 3 3]) because the remaining target (2) is less than the last number added (3), so you return up.
You repeat this sequence with a 7 in the 6th slot, overwriting the underlying array index again. Your second solution becomes [2 2 2 2 2 7 3 3], because you're still using the same underlying array. You find this solution also won't work, and return up.
After this point, you return up to before the list slice was greater than 4 in length (which is when the slice grew, by default it grows by doubling in size), meaning you're using a different (previous) backing array, which is why further iterations do not further change the existing solutions. By luck, none of the remaining solutions collide in a similar fashion.
This alternative print version shows you where the backing array changes (by showing where the address of the first entry changes): https://play.golang.org/p/nrgtMyqwow. As you can see, it changes when you grow beyond lengths 2, 4, and 8, but as you return upwards, you end up reverting back to different backing arrays.
The easiest solution to fix your specific problem is to copy the list slice before adding it to the solution set:
if target == 0 {
sol := make([]int, len(list))
copy(sol, list)
*resultp = append(*resultp, sol)
return
}
https://play.golang.org/p/3qTKoAumj0
[[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

Resources