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.)
Related
I have a simple array with values [1, 2, 3], and I'd like to find all permutations. I don't understand why moving 'copying' part of the code before the loop breaks the program.
func generatePermutations(curr, remains []int) [][]int {
if len(remains) == 0 {
return [][]int{curr}
}
var res [][]int
// DOESN'T WORK
c, r := make([]int, len(curr)), make([]int, len(remains))
copy(c, curr)
copy(r, remains)
for i := 0; i < len(remains); i++ {
// WORKS
//c, r := make([]int, len(curr)), make([]int, len(remains))
//copy(c, curr)
//copy(r, remains)
curr = append(curr, remains[i])
res = append(res, generatePermutations(curr, append(append(remains[:i]), remains[i+1:]...))...)
curr = c
remains = r
}
return res
}
When copy is outside the loop the result is the following:
[[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 3 3] [3 3 3]]
When copy is inside the loop the result is the following:
[[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 1 2] [3 2 1]]
In the first output there are two arrays with [3,3,3] which is wrong
You say that I neither modify "c" or "r" nor append to them, which is partially true.
In the first iteration of the loop,
the slices c and curr point to different backing arrays, so this is fine.
But when you do
curr = c
a bit later, you're actually assigning both slices to point to the same backing array.
This means that on the second iteration, your append could modify both c and curr ("could" because a resize would change the backing array for curr).
This is what's causing the strange behavior you see above.
Slices in go are a bit tricky, so when you know you'll be mutating and passing them around, it's better to avoid assignments, but rather stick to copying them entirely (as you do in the "WORKS" case).
For further reading this is a nice resource: https://go.dev/blog/slices-intro
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'm going through the basics of go, found this in the tour here.
I don't understand why the array values are not 0 or nil after s = s[:0]
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
output :
len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]
A slice is a view on an array. A slice will only create a new larger array and copy contents if the capacity is exceeded. A slice will continue using its original array if you truncate it. When you create a smaller slice, it is still using the old backing array with the contents leftover from the previous operations. When you append to that slice, it will continue using the same array until you exceed capacity.
This question already has answers here:
Slice chunking in Go
(8 answers)
Closed 8 months ago.
I'm recently using Go to create applications. My question is this: at a certain point in the program I have a string slice:
my_slice = []string{"string1","string2","string3","string4","string5","string6"}
It contains 6 strings. Which is the best procedure (easier to write and understand) to break this slice into 3 parts, for example, and distribute the content in three sub-slices?
If I have:
var my_sub_slice1 []string
var my_sub_slice2 []string
var my_sub_slice3 []string
I wish at the end of it my_sub_slice1 will contain (in his first two entries) "string1","string2"; my_sub_slice2 will contain (in his first two entries) "string3","string4"; my_sub_slice3 will contain (in his first two entries) "string5","string6".
I know the question is easy but I haven't found a clean and efficient way to do this yet.
Thanks a lot!
A general solution to split a slice to into sub-slices of equal length
s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
size := 2
var j int
for i := 0; i < len(s); i += size{
j += size
if j > len(s) {
j = len(s)
}
// do what do you want to with the sub-slice, here just printing the sub-slices
fmt.Println(s[i:j])
}
// output
// [1 2]
// [3 4]
// [5 6]
// [7 8]
// [9 10]
my_sub_slice1 := my_slice[0:2]
my_sub_slice2 := my_slice[2:4]
my_sub_slice3 := my_slice[4:6]
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]