1

The key difference between this question and the lots of duplicated answers is that, the input array is short, only 3 elements. --

Say I have an ordered set of int. The size of array is only 3 (or a bit more). I need to randomize their order and return a new array. Although it is a pure algorithm question, but the prefered answer language is in Go.

However, this is my code:

https://go.dev/play/p/CVu8_Q96-9F

func randShuffle(a []int) {
    rand.Seed(time.Now().UnixNano())
    rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
}

And this is one of my test run result:

[2 1 3]
[1 3 2]
[2 1 3]
[2 1 3]
[1 3 2]
[1 2 3]
[2 3 1]

which doesn't seems to be very randomized.

Any good idea to have a better randomization for a short 3-elements array?

BTW,

Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45
xpt
  • 20,363
  • 37
  • 127
  • 216
  • 3
    it won't "look" random because there are only three elements. rand.Shuffle uses the Fisher-Yates algorithm under the hood. if you implement that on your own, you will see similar results. – skeeter Mar 30 '23 at 14:16
  • 1
    Here's the implementation of `math.rand.Shuffle`, which does say that it uses Fisher-Yates: https://github.com/golang/go/blob/master/src/math/rand/rand.go#L244-L267 – Solomon Ucko Mar 30 '23 at 14:19
  • 4
    _"which doesn't seems to be very randomized"_ -- how are you determining that? random doesn't mean evenly distributed, it means random which the output fits just fine. If you want to measure it run it a a million times and plot the histogram. – JimB Mar 30 '23 at 14:29
  • 1
    Try running it a lot of times and count how many times each permutation occurs. – Solomon Ucko Mar 30 '23 at 14:29
  • 1
    Ask yourself: how man different permutations of 1, 2, 3 are there? Write them down all. Select one of these permutations randomly (no need to shuffle). – Volker Mar 30 '23 at 15:09

1 Answers1

1

Move random.Seed from your shuffle function to the main. Seeding of a PRNG should only be done once per program, the successful mimicry of randomness is done by the state transitions of the generator rather than by the seed. Don't re-seed unless you really understand how PRNGs work and are trying to explicitly control the process for reasons such as reproducibility.

The following straightforward modification of your code should meet your needs:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())

    a := []int{1, 2, 3}
    for i := 0; i < 10; i++ {
        randShuffle(a)
        fmt.Println(a)
    }
}

func randShuffle(a []int) {
    rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
}

This produces results such as:

[2 3 1]
[3 1 2]
[2 1 3]
[2 3 1]
[1 2 3]
[1 3 2]
[1 2 3]
[3 1 2]
[3 2 1]
[2 3 1]
pjs
  • 18,696
  • 4
  • 27
  • 56
  • BINGO! Thanks for spotting the tiny detail that others failed to have identified! – xpt Apr 03 '23 at 14:56