Skip to content

Instantly share code, notes, and snippets.

@quux00
Last active February 13, 2019 10:33
Show Gist options
  • Save quux00/8258425 to your computer and use it in GitHub Desktop.
Save quux00/8258425 to your computer and use it in GitHub Desktop.
Knuth Fisher-Yates shuffle for Go (golang)
// implements Knuth or Fisher-Yates shuffle
package knuth
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func Shuffle(slc []interface{}) {
N := len(slc)
for i := 0; i < N; i++ {
// choose index uniformly in [i, N-1]
r := i + rand.Intn(N-i)
slc[r], slc[i] = slc[i], slc[r]
}
}
func ShuffleInts(slc []int) {
N := len(slc)
for i := 0; i < N; i++ {
// choose index uniformly in [i, N-1]
r := i + rand.Intn(N-i)
slc[r], slc[i] = slc[i], slc[r]
}
}
func ShuffleStrings(slc []string) {
N := len(slc)
for i := 0; i < N; i++ {
// choose index uniformly in [i, N-1]
r := i + rand.Intn(N-i)
slc[r], slc[i] = slc[i], slc[r]
}
}
@marktheunissen
Copy link

I think this has a flaw as it doesn't match the pseudocode:

To shuffle an array a of n elements (indices 0..n-1):
  for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ i
       exchange a[j] and a[i]

Try this:

rand.Seed(time.Now().UnixNano())
n := len(slice)
for i := n - 1; i > 0; i-- {
    j := rand.Intn(i + 1)
    slice[i], slice[j] = slice[j], slice[i]
}

@quux00
Copy link
Author

quux00 commented Sep 13, 2014

You were right - there was a flaw in the original implementation. Your version looks correct. There is also a way to do it by counting up instead of down. I based my revised version on Bob Sedgewick's version: http://algs4.cs.princeton.edu/11model/Knuth.java.html

@dolmen
Copy link

dolmen commented Nov 12, 2015

rand.Seed should not be called in the package.
If it has to be done, it must be done just once per program in the main package. Because if every package that uses rand calls Seed, it may be called many times, while once is enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment