How to properly copy arrays when using backtracking algorithm in Golang? - arrays

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

Related

some question about append built-in function

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.)

How to split a slice in Go in sub-slices [duplicate]

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]

selecting 2D sub-slice of a 2D-slice using ranges in go

I'm getting a surprising result when selecting a 2D sub-slice of a slice.
Consider the following 2D int array
a := [][]int{
{0, 1, 2, 3},
{1, 2, 3, 4},
{2, 3, 4, 5},
{3, 4, 5, 6},
}
To select the top left 3x3 2D slice using ranges I would use
b := a[0:2][0:2]
I would expect the result to be
[[0 1 2] [1 2 3] [2 3 4]]
however the second index range doesn't seem to have any effect, and returns the following instead:
[[0 1 2 3] [1 2 3 4] [2 3 4 5]]
What am I missing? Can you simply not select a sub-slice like this where the dimension > 1 ?
You can't do what you want in a single step. Slices and arrays are not 2-dimensional, they are just composed to form a multi-dimensional object. See How is two dimensional array's memory representation
So with a slice expression, you just get a slice that will hold a subset of the "full" rows, and its type will be the same: [][]int. If you slice it again, you just slicing the slice of rows again.
Also note that the higher index in a slice expression is exclusive, so a[0:2] will only have 2 rows, so you should use a[0:3] or simply a[:3] instead.
To get what you want, you have to slice the rows individually like this:
b := a[0:3]
for i := range b {
b[i] = b[i][0:3]
}
fmt.Println(b)
This will output (try it on the Go Playground):
[[0 1 2] [1 2 3] [2 3 4]]
Or shorter:
b := a[:3]
for i, bi := range b {
b[i] = bi[:3]
}

Slice array of arbitrary dimension with lists of start and end indices

I need to copy a part of a 3D array.
I have the indexes of start and end of the copy.
For example 2D array:
[[2 2 3 4 5]
[2 3 3 4 5]
[2 3 4 4 5]
[2 3 4 5 5]
[2 3 4 5 6]]
starting index, end index are:
mini = [2, 1]
maxi = [4, 3]
So the result should be:
[[3 4 4]
[3 4 5]]
I can write:
result = matrix[mini[0]:maxi[0], mini[1]:maxi[1]]
Is there a way to do it generally ? for 3Dim or NDim arrays ?
The trick here is realizing what the indexing syntax is under the hood. This:
result = matrix[mini[0]:maxi[0], mini[1]:maxi[1]]
Is shorthand in python (not just numpy) for:
indices = slice(mini[0], maxi[0]), slice(mini[1], maxi[1])
result = matrix[indices]
So we just need to generate indices dynamically:
lower = [2, 1, ...]
upper = [4, 3, ...]
indices = tuple(np.s_[l:u] for l, u in zip(lower, upper))
result = matrix_nd[indices]
np.s_[a:b] is a shorthand for slice(a, b). Here we build a tuple containing as many slices as you have values in lower and upper
What you are looking for is the slice object, see that example:
matrix = np.random.rand(4,5)
mini = [2, 1]
maxi = [4, 3]
slices=[slice(b,e) for b, e in zip(mini,maxi)]
print(slices)
print(matrix[slices])
print(matrix[mini[0]:maxi[0], mini[1]:maxi[1]])

Removing elements from a cell array in MATLAB

I have a cell array as shown below:
a = {[1 2 3] [5 3 6] [9 1 3]};
Now I want to remove the 1s from every array in a that contains 1 so that the output is as shown
a = {[2 3] [5 3 6] [9 3]};
I know the indices of arrays in cell array 'a' which contain 1. This can be done using for loop and a temporary variable, but this is taking a lot of time (I want to perform the operation on a cell array of size something like 1x100000. The one above is just for an example)
I want to know if there is any direct method that can do this quickly.
Pretty much anything is going to be slow with that large of a cell array. You could try to do this with cellfun but it's not necessarily guaranteed to be any faster than a for loop.
a = cellfun(#(x)x(x ~= 1), a, 'UniformOutput', false);
% a{1} =
% 2 3
% a{2} =
% 5 3 6
% a{3} =
% 9 3
As already commented by Suever, because you are using a cell array and it is a dynamic container, you don't have a choice but to iterate through each cell if you want to modify the contents. Just to be self-contained, here is the for loop approach to do things:
for ii = 1 : numel(a)
a{ii} = a{ii}(a{ii} ~= 1);
end
This may be faster as it doesn't undergo the overhead of cellfun. The code above accesses the vector in each cell and extracts out those values that are not equal to 1 and overwrites the corresponding cell with this new vector.
Using your example:
a = {[1 2 3] [5 3 6] [9 1 3]};
We get:
>> format compact; celldisp(a)
a{1} =
2 3
a{2} =
5 3 6
a{3} =
9 3
This example shows how to remove data from individual cells, and how to delete entire cells from a cell array. To run the code in this example, create a 3-by-3 cell array:
C = {1, 2, 3; 4, 5, 6; 7, 8, 9};
Delete the contents of a particular cell by assigning an empty array to the cell, using curly braces for content indexing, {}:
C{2,2} = []
This code returns
C =
[1] [2] [3]
[4] [] [6]
[7] [8] [9]
Delete sets of cells using standard array indexing with smooth parentheses, (). For example, this command
C(2,:) = []
removes the second row of C:
`
C =
[1] [2] [3]
[7] [8] [9]`

Resources