My problem is the answer should has [1 1 2 2], but it got [1 1 2 3].
I debuged this code, found that in that loop, [1 1 2 2] was appended to the array firstly, but it changed to [1 1 2 3] in next loop.
I don't understand why, the log which started with 'D', the elements in this array changed in next loop.
Here is my code:
https://play.golang.org/p/X_CU8GlMOqf
package main
import (
"fmt"
)
func main() {
nums := []int{1, 1, 2, 2, 3}
result := subsetsWithDup(nums)
fmt.Println(result)
}
func subsetsWithDup(nums []int) [][]int {
result := [][]int{{}, nums}
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := 1; j < len(nums); j++ {
result = append(result, dsf(nums, []int{nums[i]}, i+1, j)...)
}
}
return result
}
func dsf(nums []int, set []int, start int, length int) [][]int {
result := [][]int{}
if len(set) == length {
return append(result, set)
}
for i := start; i < len(nums); i++ {
if i != start && nums[i] == nums[i-1] {
continue
}
if len(set) == 3 {
fmt.Printf("A %v %p\n", result, &result)
}
tmp := set[:]
tmp = append(tmp, nums[i])
if len(set) == 3 {
fmt.Printf("B %v %p %v %p\n", tmp, &tmp, result, &result)
}
result = append(result, dsf(nums, tmp, i+1, length)...)
if len(tmp) == 4 {
fmt.Printf("C %v %p %v %p\n", tmp, &tmp, result, &result)
for _, r := range result {
fmt.Printf("D %v %p\n", r, &r)
}
}
}
return result
}
A [] 0xc000004960
B [1 1 2 2] 0xc0000049c0 [] 0xc000004960
C [1 1 2 2] 0xc0000049c0 [[1 1 2 2]] 0xc000004960
D [1 1 2 2] 0xc000004ae0
A [[1 1 2 2]] 0xc000004960
B [1 1 2 3] 0xc000004b60 [[1 1 2 3]] 0xc000004960
C [1 1 2 3] 0xc000004b60 [[1 1 2 3] [1 1 2 3]] 0xc000004960
D [1 1 2 3] 0xc000004ca0
D [1 1 2 3] 0xc000004ca0
A [] 0xc000004da0
B [1 2 2 3] 0xc000004de0 [] 0xc000004da0
C [1 2 2 3] 0xc000004de0 [[1 2 2 3]] 0xc000004da0
D [1 2 2 3] 0xc000004f00
You are trying to copy a slice with:
tmp := set[:]
This does not copy the slice, it re-uses the original slice. It has the same effect as tmp := set. You can use:
tmp := append([]int(nil), set...)
if you like. Here is your program with this change, and all the extra debug commented out.
Related
I have some code in golang which is suppose to discover the next possibilities in a Tic-Tac-Toe board.
This is the buggy part:
var next []State
for row := 0; row < len(board); row++ {
for place := 0; place < len(board[row]); place++ {
if board[row][place] == 0 {
nPos := board
fmt.Print(nPos)
nPos[row][place] = play
fmt.Print(nPos, row, place, play, "\n")
next = append(next, nPos)
}
}
}
State is a type of [][]int.
board is a State, play is an int and next is a []State .
The output is as follows:
[[0 0 0] [0 0 0] [0 0 0]][[1 0 0] [1 0 0] [1 0 0]] 0 0 1
[[1 0 0] [1 0 0] [1 0 0]][[1 1 0] [1 1 0] [1 1 0]] 0 1 1
[[1 1 0] [1 1 0] [1 1 0]][[1 1 1] [1 1 1] [1 1 1]] 0 2 1
[[[1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1]]]
You can clearly see two things:
One iteration changes the whole column (I guess it has to do with the outer loop, row)
For some reason the changes are saved (nPos is not reinitialized through iterations)
I am somewhat new to Go, am I wrong when expect nPos to be a new variable in every iteration?
I have already looked for issues in the line nPos[row][place] = play, but apparently no specific line causes the issue. I guess it is just the scope.
As #zerkms pointed out:
nPos := board <--- here both nPos, and board contain the same slice, Go does not implicitly do a deep slice copy. If you want a duplicate of a slice - you should manually clone it.
One option is:
cpy := make([]T, len(orig)) copy(cpy, orig)
Other answers are here:
Concisely deep copy a slice?
I have a map with arrays for keys.
I want to add all of the keys/arrays to a slice of slices.
However, I am getting unexpected results.
Code:
package main
import "fmt"
func main() {
var finalResult [][]int
set := make(map[[2]int]int)
a, b, c := [2]int{1, 1}, [2]int{2, 2}, [2]int{3, 3}
set[a], set[b], set[c] = 1, 1, 1
fmt.Println("set: ", set)
for x := range set {
fmt.Println("\nfinalResult 0: ", finalResult)
fmt.Println("x: ", x[:])
finalResult = append(finalResult, x[:])
fmt.Println("finalResult 1: ", finalResult)
}
}
Output:
set: map[[1 1]:1 [2 2]:1 [3 3]:1]
finalResult 0: []
x: [1 1]
finalResult 1: [[1 1]]
finalResult 0: [[2 2]]
x: [2 2]
finalResult 1: [[2 2] [2 2]]
finalResult 0: [[3 3] [3 3]]
x: [3 3]
finalResult 1: [[3 3] [3 3] [3 3]]
finalResult appears to be changing during the for loop?
Can someone explain what is happening and how I can work around this issue?
The problem is, that you append the x local variable to the finalResult, which is a pointer, so in every for loop, the x will point to a new array in the memory. When you add this x three times to the finalResult and print it, all the three x will be points to the same memory address. You have to copy the content where x points in every loop to a new variable and add this to the finalResult.
package main
import "fmt"
func main() {
var finalResult [][]int
set := make(map[[2]int]int)
a, b, c := [2]int{1, 1}, [2]int{2, 2}, [2]int{3, 3}
set[a], set[b], set[c] = 1, 1, 1
fmt.Println("set: ", set)
for x := range set {
fmt.Println("\nfinalResult 0: ", finalResult)
fmt.Println("x: ", x[:])
a := make([]int, 2)
copy(a, x[:])
finalResult = append(finalResult, a)
fmt.Println("finalResult 1: ", finalResult)
}
}
But be aware, that ranging over a map will be always in random order, so your final result may change on every run.
package main
import (
"fmt"
)
func main() {
result := subsets([]int{9,3,0,1,2})
fmt.Println(result)
}
func subsets(nums []int) [][]int {
result := [][]int{}
var fun func([]int, int)
fun = func (preSets []int, start int) {
// fmt.Println(start, preSets, result)
result = append(result, preSets)
// fmt.Println(result)
for idx := start; idx < len(nums); idx++ {
tmp := nums[idx]
newSet := append(preSets, tmp)
fun(newSet, idx+1)
newSet = newSet[:len(newSet) - 1]
}
}
fun([]int{}, 0)
return result
}
i want to find the subsets of a slice, and think the code above should work. but it give me the following output
[[] [9] [9 3] [9 3 0] [9 3 0 2] [9 3 0 1 2] [9 3 0 2] [9 3 1] [9 3 1 2] [9 3 2] [9 0] [9 0 1] [9 0 1 2] [9 0 2] [9 1] [9 1 2] [9 2] [3] [3 0] [3 0 1] [3 0 1 2] [3 0 2] [3 1] [3 1 2] [3 2] [0] [0 1] [0 1 2] [0 2] [1] [1 2] [2]]
the fifth slice should be [9 3 0 1], but it is [9 3 0 2],and i print the result each step, i found out that the fifth slice turned from [9301] to [9302] when the seventh slice [9302] is appended,i think it should be related to the array storage under the slice, but why
i think [the problem is] related to the array storage under the slice
Yes, it is.
but why
The append function:
sometimes re-uses the original backing array, but
sometimes creates a new backing array and copies the original values to the new array.
There are no promises made about when it does one of these two.
When it re-uses the original array, you encounter the behavior you dislike. When it makes a new array, you encounter the behavior you desire. Since you want the copy behavior, you can simply write your own "always copy" code and get the behavior you want. However, a more-minimal change is to replace:
result = append(result, preSets)
with:
result = append(result, unshare(preSets))
with the function unshared defined as:
func unshare(a []int) []int {
tmp := make([]int, len(a))
copy(tmp, a)
return tmp
}
If you are trying to explain to yourself exactly why you got the exact result that you got, it's a little tricky because you're not promised anything about when append makes a new backing array and when it re-uses the existing backing array—but it is explainable, if you make the following two assumptions:
append never makes a copy of the backing array if it does not have to; and
when append does make a copy, it sometimes over-allocates the new backing array by some factor.
That is, append behaves more or less like this, except of course this one is specific to []int:
func xappend(orig []int, add []int) []int {
has := len(orig)
needed := has + len(add)
// If we can fit the added elements in, do that now.
if cap(orig) >= needed {
fmt.Println("copy in place")
orig = orig[:needed]
copy(orig[has:needed], add)
return orig
}
newSize := undocumentedFunction(has, cap(orig), needed)
fmt.Println("make new, size", newSize)
new := make([]int, needed, newSize)
copy(new, orig)
copy(new[has:needed], add)
return new
}
func undocumentedFunction(oldCap, oldLen, newCap int) int {
twiceAsMuch := oldCap + oldCap
if newCap > twiceAsMuch {
return newCap
}
// 2x old capacity is enough, but
// we'll tweak this in various ways.
// The exact tweaks might change at any time.
if oldLen < 1024 {
return twiceAsMuch
}
panic("didn't copy this part")
}
This "undocumented function" is part of the runtime system, and it collaborates with the compiler. You can see its actual code here (note: this link may break or go to the wrong line at some point).
(Sample runnable code here on the Go Playground.)
So the code works fine if I'm trying to find the size of the land in the middle, but it fails when calculating the size of the small land in the corner. How do I return 0 if it starts checking for land outside of the given arrays?
M = 'land'
o = 'water'
world = [[o,o,o,o,o,o],
[o,M,M,M,o,o],
[o,o,M,M,o,o],
[o,o,o,o,o,M]]
def continent_size world, x, y
if world[x][y] != 'land'
return 0
end
size = 1
world[x][y] = 'counted land'
size = size + continent_size(world, x-1, y-1)
size = size + continent_size(world, x , y-1)
size = size + continent_size(world, x+1, y-1)
size = size + continent_size(world, x-1, y )
size = size + continent_size(world, x+1, y )
size = size + continent_size(world, x-1, y+1)
size = size + continent_size(world, x , y+1)
size = size + continent_size(world, x+1, y+1)
size
end
puts continent_size(world, 3, 5)
How about some guard clauses at the top of your method like:
# make sure we don't attempt to index into an array at less than zero
return 0 if x < 0
return 0 if y < 0
# make sure there is a value in the requested slot
return 0 unless world[x]
return 0 unless world[x][y]
def continent_size(world, row, col)
rows = ([row-1, 0].max..[row+1, world.size-1].min).to_a
cols = ([col-1,0].max..[col+1, world.first.size-1].min).to_a
rows.product(cols).count { |r,c| world[r][c] == M }
end
world.size.times { |r| world.first.size.times { |c|
puts "[#{r},#{c}] -> #{continent_size(world, r, c)}" } }
[0,0] -> 1
[0,1] -> 2
[0,2] -> 3
[0,3] -> 2
[0,4] -> 1
[0,5] -> 0
[1,0] -> 1
[1,1] -> 3
[1,2] -> 5
[1,3] -> 4
[1,4] -> 2
[1,5] -> 0
[2,0] -> 1
[2,1] -> 3
[2,2] -> 5
[2,3] -> 4
[2,4] -> 3
[2,5] -> 1
[3,0] -> 0
[3,1] -> 1
[3,2] -> 2
[3,3] -> 2
[3,4] -> 2
[3,5] -> 1
For
row = 0
col = 3
the steps are as follows. (Note world_size #=> 4 and world.first.size #=> 6.)
rows = ([row-1, 0].max..[row+1, world.size-1].min).to_a
#=> ([-1,0].max..[1,3].min).to_a
#=> (0..1).to_a
#=> [0, 1]
cols = ([col-1,0].max..[col+1,world[0].size-1].min).to_a
#=> ([2,0].max..[4,5].min).to_a
#=> (2..4).to_a
#=> [2,3,4]
a = rows.product(cols)
#=> [[0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4]]
a.count { |r,c| world[r][c] == M }
#=> 2
Is there any built-in function in Go for copying one array to another?
Will this work in case of two (or more) dimensional arrays?
Is there any built-in function in Go language for copying one array to another?
Yes: http://play.golang.org/p/_lYNw9SXN5
a := []string{
"hello",
"world",
}
b := []string{
"goodbye",
"world",
}
copy(a, b)
// a == []string{"goodbye", "world"}
Will this work in case of two (or more) dimensional arrays?
copy will do a shallow copy of the rows: http://play.golang.org/p/0gPk6P1VWh
a := make([][]string, 10)
b := make([][]string, 10)
for i := range b {
b[i] = make([]string, 10)
for j := range b[i] {
b[i][j] = strconv.Itoa(i + j)
}
}
copy(a, b)
// a and b look the same
b[1] = []string{"some", "new", "data"}
// b's second row is different; a still looks the same
b[0][0] = "apple"
// now a looks different
I don't think there's a built-in for doing deep-copys of multi-dimensional arrays: you can do it manually like: http://play.golang.org/p/nlVJq-ehzC
a := make([][]string, 10)
b := make([][]string, 10)
for i := range b {
b[i] = make([]string, 10)
for j := range b[i] {
b[i][j] = strconv.Itoa(i + j)
}
}
// manual deep copy
for i := range b {
a[i] = make([]string, len(b[i]))
copy(a[i], b[i])
}
b[0][0] = "apple"
// a still looks the same
edit: As pointed out in the comments, I assumed by "copy an array" you meant "do a deep copy of a slice", as arrays can be deep-copied with the = operator as per jnml's answer (because arrays are value types): http://play.golang.org/p/8EuFqXnqPB
The primary "function" for copying an array in Go is the assignment operator =, as it is the case for any other value of any other type.
package main
import "fmt"
func main() {
var a, b [4]int
a[2] = 42
b = a
fmt.Println(a, b)
// 2D array
var c, d [3][5]int
c[1][2] = 314
d = c
fmt.Println(c)
fmt.Println(d)
}
Playground
Output:
[0 0 42 0] [0 0 42 0]
[[0 0 0 0 0] [0 0 314 0 0] [0 0 0 0 0]]
[[0 0 0 0 0] [0 0 314 0 0] [0 0 0 0 0]]
Use copy http://play.golang.org/p/t7P6IliMOK
a := []int{1, 2, 3}
var b [3]int
fmt.Println("A:", a)
fmt.Println("B:", b)
copy(b[:], a)
fmt.Println("A:", a)
fmt.Println("B2:", b)
b[1] = 9
fmt.Println("A:", a)
fmt.Println("B3:", b)
OUT:
A: [1 2 3]
B: [0 0 0]
A: [1 2 3]
B2: [1 2 3]
A: [1 2 3]
B3: [1 9 3]