What is a clean way of taking a random sample, without replacement from an array in javascript? So suppose there is an array
x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
and I want to randomly sample 5 unique values; i.e. generate a random subset of length 5. To generate one random sample one could do something like:
x[Math.floor(Math.random()*x.length)];
But if this is done multiple times, there is a risk of a grabbing the same entry multiple times.
Or... if you use underscore.js...
Simple enough.
Here is another implementation based on Fisher-Yater Shuffle. But this one is optimized for the case where the sample size is significantly smaller than the array length. This implementation doesn't scan the entire array nor allocates arrays as large as the original array. It uses sparse arrays to reduce memory allocation.
A little late to the party but this could be solved with underscore's new sample method (underscore 1.5.2 - Sept 2013):
In my opinion, I do not think shuffling the entire deck necessary. You just need to make sure your sample is random not your deck. What you can do, is select the
size
amount from the front then swap each one in the sampling array with another position in it. So, if you allow replacement you get more and more shuffled.This algorithm is only
2*size
steps, if you include theslice
method, to select the random sample.More Random
To make the sample more random, we can randomly select the starting point of the sample. But it is a little more expensive to get the sample.
What makes this more random is the fact that when you always just shuffling the front items you tend to not get them very often in the sample if the sampling array is large and the sample is small. This would not be a problem if the array was not supposed to always be the same. So, what this method does is change up this position where the shuffled region starts.
No Replacement
To not have to copy the sampling array and not worry about replacement, you can do the following but it does give you
3*size
vs the2*size
.No Replacement and More Random
To apply the algorithm that gave a little bit more random samples to the no replacement function:
Faster...
Like all of these post, this uses the Fisher-Yates Shuffle. But, I removed the over head of copying the array.
If you're using lodash the API changed in 4.x:
https://lodash.com/docs#sampleSize
You can get a 5 elements sample by this way:
You can define it as a function to use in your code:
Or add it to the Array object itself:
if you want, you can separate the code for to have 2 functionalities (Shuffle and Sample):