# Fischer Yates shuffle in coffee-script

Assuming that `Math.random()` produces evenly distributed random numbers between 0 and 1, is this a correct implementation of the Fischer Yates shuffle? I am looking for a very random, even distribution, where the number of shuffled elements in an input array (`arr`) can be specified (as `required`).

``````shuffle = (arr, required)->
rnd = (int) ->
r = Math.random() * int
Math.round r

len = arr.length-1

for i in [len..1]
random = rnd(i)
temp = arr[random]
arr[random] = arr[i]
arr[i] = temp
break if i < len - (required - 2)

return arr
``````

## 评论

### A couple things: Rather th

A couple things:

• Rather than `Math.round()`, try `Math.floor()`; in your implementation `Math.round()` gives the first element (at index 0) and the last element less of a chance than all the other elements (.5/len vs. 1/len). Note that on the first iteration, you input `arr.length - 1` for `arr.length` elements.
• If you're going to have a `required` variable, you might as well make it optional, in that it defaults to the length of the array: ```shuffle = (arr, required=arr.length)```
• You return the entire array even though you only shuffled the last elements. Consider instead returning `arr[arr.length - required ..]`
• What if `required` isn't in the range `[0,arr.length]`?

Putting it all together (and adding some flair):

``````    shuffle = (arr, required=arr.length) ->
randInt = (n) -> Math.floor n * Math.random()
required = arr.length if required > arr.length
return arr[randInt(arr.length)] if required <= 1

for i in [arr.length - 1 .. arr.length - required]
index = randInt(i+1)
# Exchange the last unshuffled element with the
# selected element; reduces algorithm to O(n) time
[arr[index], arr[i]] = [arr[i], arr[index]]

# returns only the slice that we shuffled
arr[arr.length - required ..]

# Let's test how evenly distributed it really is
counter = [0,0,0,0,0,0]
permutations = ["1,2,3","1,3,2","2,1,3","2,3,1","3,2,1","3,1,2"]
for i in [1..12000]
x = shuffle([1,2,3])
counter[permutations.indexOf("#{x}")] += 1

``````