#Why do the elements start to repeat for length >= 4?

19 messages · Page 1 of 1 (latest)

restive hollow
#
func cross(s1 [][]uint, s2 []uint) [][]uint {
    s1CrossS2 := [][]uint{}

    for _, s1Elem := range s1 {
        for _, s2Elem := range s2 {
            if !sliceContains(s1Elem, s2Elem) {
                s1ElemUpdated := append(s1Elem, s2Elem)
                s1CrossS2 = append(s1CrossS2, s1ElemUpdated)
            }
        }
    }

    return s1CrossS2
}

func indexPermutations(sample []uint, k uint) [][]uint {
    // If something is not possible, then it's empty. BiG bReN
    if uint(len(sample)) < k {
        return [][]uint{}
    }

    space := [][]uint{{}}

    for range k {
        space = cross(space, sample)
        fmt.Println(space)
        fmt.Println()
    }

    return space
}

func sliceContains[T comparable](slice []T, item T) bool {
    for _, v := range slice {
        if v == item {
            return true
        }
    }

    return false
}
#

Suppose my main function is

    a := []uint{1, 2, 3, 4, 5, 6, 7}
    k := uint(4)
    r := indexPermutations(a, k)

If I print r, every element appears 4 times. Why?

#

From this of code from the indexPermutations function,```go
for range k {
space = cross(space, sample)
fmt.Println(space)
fmt.Println()
}

I can see that it does start off as intended but then it starts repeating elements after length >= 4
#

Not sure why

#

I have a python version too if anyone would like to see that.

median horizon
#

because you are writing to s1elem 4 times

#

slices are mutable types that share a pointer to an underlyign array
s1ElemUpdated := append(s1Elem, s2Elem)
may or may not create a new underlying array, depending on cap(s1Elem)

#

for instance (tho in the example I need to be more explicit to show what's going on):

a := make([]int, 2, 4) // len = 2, cap = 4
a[0] = 1
a[1] = 2
fmt.Println(a) // easy so far

fmt.Println(append(a, 10)) // a can fit 4 elements (per the cap), a[2] is now 10
fmt.Println(append(a, 20)) // a can fit 4 elements (per the cap), a[2] is now 20
fmt.Println(append(a, 30)) // a can fit 4 elements (per the cap), a[2] is now 30

fmt.Println(a[:cap(a)]) // we need to extend a's length explicitly here to see the new elements
#

in short:

  • a slice is a type slice struct { ptr *T; len, cap int }
  • append always returns a new slice
  • the new slice will point to the same data so long as it has sufficient capacity to hold the new elements, otherwise a new backing array will be allocated
#

everything in go is passed by value, meaning everything is copied
but a pointer is "just a number", so copying it only copies the address, not what it points to
pointer types and types with inner pointers act like reference types, they are sharing data

restive hollow
#

What's the ideal way to prevent this from happening?
The one I can think of is to make an empty array with more length and then copy data but it doesn't sound ideal.

median horizon
#

"ideal" is ill defined
if you don't want to share data the solution is to not share data :p

explicitly allocating a new slice is certainly the most straightforward option

#

you are doing so implicitly here: go s1CrossS2 = append(s1CrossS2, s1ElemUpdated)

restive hollow
median horizon
#

just append to that isnteadof s1

restive hollow
median horizon
#

oh I missread it, they are not the same type

restive hollow
#

Oh by the way @median horizon, thanks for telling me about this. I wouldn't have known about this without you :)
The bug has been fixed now.