Browse files

Replace hackish generators/shuffle with a fisher-yates implementation


    (sort (fn [_] (long)) coll)

Does not work on JDK7 since TimSort is clever enough to detect that the
ordering function is behaving inconsistently, resulting in:

    Comparison method violates its general contract!

Also, this is just a bad idea:

    A variant of the above method that has seen some use in languages
    that support sorting with user-specified comparison functions is
    to shuffle a list by sorting it with a comparison function that
    returns random values. However, this is an extremely bad method:
    it is very likely to produce highly non-uniform distributions,
    which in addition depends heavily on the sorting algorithm used.–Yates_shuffle#Comparison_with_other_shuffling_algorithms

We can't use clojure.core/shuffle since we want whatever shuffling we
do to be repeatable given the same input and same initial state of the
random number generator.

This patch provides an implementation of the fisher-yates shuffle and
then replaces the body of shuffle with a call to said function.

Signed-off-by: Stuart Halloway <>
  • Loading branch information...
1 parent a73c11e commit 5a59bf0fcddde12397d575e40aea3487f1f61825 @bpsm bpsm committed with stuarthalloway Oct 11, 2012
Showing with 16 additions and 1 deletion.
  1. +16 −1 src/main/clojure/clojure/test/generative/generators.clj
17 src/main/clojure/clojure/test/generative/generators.clj
@@ -274,10 +274,25 @@ instance you can get a repeatable basis for tests."
(one-of scalar collection))
+(defn ^:private fisher-yates
+ "–Yates_shuffle#The_modern_algorithm"
+ [coll]
+ (let [as (object-array coll)]
+ (loop [i (dec (count as))]
+ (if (<= 1 i)
+ (let [j (uniform 0 (inc i))
+ t (aget as i)]
+ (aset as i (aget as j))
+ (aset as j t)
+ (recur (dec i)))
+ (into (empty coll) (seq as))))))
(defn shuffle
"Shuffle coll"
- (sort-by (fn [_] (long)) coll))
+ ;; using our own fischer-yates instead of core/shuffle so that
+ ;; we'll get the same shuffle, given the same random *seed*.
+ (fisher-yates coll))

0 comments on commit 5a59bf0

Please sign in to comment.