You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current "Shuffling Array Elements" page recommends a naive algorithm, which produces
a slow and biased shuffle. Included is a highly idiomatic refactorization of the Fisher-
Yates shuffle (aka the Knuth Shuffle), a less-idiomatic-but-better refactorization, and a
version of the algorithm that adds to Array.prototype, for those that program in that
style.
For more background on how this shuffle logic works, see this [discussion at StackOverflow](http://stackoverflow.com/questions/962802/is-it-correct-to-use-javascript-array-sort-method-for-shuffling).
39
+
### The Wrong Way to do it
40
+
41
+
There is a common--but terribly wrong way--to shuffle an array, by sorting by a random
42
+
number.
43
+
44
+
{% highlight coffeescript %}
45
+
shuffle = (a) -> a.sort -> 0.5 - Math.random()
46
+
{% endhighlight %}
47
+
48
+
If you do a sort randomly, it should give you a random order, right? Even [Microsoft used
49
+
this random-sort algorithm][msftshuffle]. Turns out, [this random-sort algorithm produces
50
+
biased results][naive], because it only has the illusion of shuffling. Randomly sorting
51
+
will not result in a neat, tidy shuffle; it will result in a wild mass of inconsistent
The solution above isn't as fast, or as lean, as it can be. The list comprehension, when
60
+
transformed into Javascript, is far more complex than it needs to be, and the
61
+
destructured assignment is far slower than dealing with bare variables. The following
62
+
code is less idiomatic, and takes up more source-code space... but will compile down
63
+
smaller and run a bit faster:
64
+
65
+
{% highlight coffeescript %}
66
+
shuffle = (a) ->
67
+
i = a.length
68
+
while --i > 0
69
+
j = ~~(Math.random() * (i + 1)) # ~~ is a common optimization for Math.floor
70
+
t = a[j]
71
+
a[j] = a[i]
72
+
a[i] = t
73
+
a
74
+
{% endhighlight %}
75
+
76
+
### Extending Javascript to include this shuffle.
77
+
78
+
The following code adds the shuffle function to the Array prototype, which means that
79
+
you are able to run it on any array you wish, in a much more direct manner.
80
+
81
+
{% highlight coffeescript %}
82
+
Array::shuffle = ->
83
+
for i in [@length-1..1]
84
+
j = Math.floor Math.random() * (i + 1)
85
+
[@[i], @[j]] = [@[j], @[i]]
86
+
@
87
+
88
+
[1..9].shuffle()
89
+
# => [ 3, 1, 5, 6, 4, 8, 2, 9, 7 ]
90
+
{% endhighlight %}
91
+
92
+
**Note:** Although it's quite common in languages like Ruby, extending native objects is
93
+
often considered bad practice in JavaScript (see: [Maintainable JavaScript: Don’t modify
94
+
objects you don’t own][dontown]; [Extending built-in native objects. Evil or not?]
95
+
[extendevil]).
96
+
97
+
Also, if you think you'll be using a lot of these utility functions, consider using a
98
+
utility library, like [Lo-dash](http://lodash.com/). They include a lot of nifty
99
+
features, like maps and forEach, in a cross-browser, lean, high-performance way.
24
100
25
-
**Note:** Although it's quite common in languages like Ruby, extending native objects is often considered bad practice in JavaScript (see: [Maintainable JavaScript: Don’t modify objects you don’t own](http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/); [Extending built-in native objects. Evil or not?](http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/)).
0 commit comments