Sampling a random subset from an array
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.
javascript arrays random numerical-methods
add a comment |
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.
javascript arrays random numerical-methods
I noticed Avi Moondra's bl.ock uses this technique
– The Red Pea
Aug 27 '16 at 3:36
add a comment |
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.
javascript arrays random numerical-methods
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.
javascript arrays random numerical-methods
javascript arrays random numerical-methods
edited Aug 13 '12 at 14:04
Zheileman
2,2991620
2,2991620
asked Aug 13 '12 at 13:25
JeroenJeroen
16.3k3093160
16.3k3093160
I noticed Avi Moondra's bl.ock uses this technique
– The Red Pea
Aug 27 '16 at 3:36
add a comment |
I noticed Avi Moondra's bl.ock uses this technique
– The Red Pea
Aug 27 '16 at 3:36
I noticed Avi Moondra's bl.ock uses this technique
– The Red Pea
Aug 27 '16 at 3:36
I noticed Avi Moondra's bl.ock uses this technique
– The Red Pea
Aug 27 '16 at 3:36
add a comment |
10 Answers
10
active
oldest
votes
I suggest shuffling a copy of the array using the Fisher-Yates shuffle and taking a slice:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(0, size);
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
Note that this will not be the most efficient method for getting a small random subset of a large array because it shuffles the whole array unnecessarily. For better performance you could do a partial shuffle instead:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index;
while (i-- > min)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(min);
1
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
@AaronJo: No, that's deliberate.i
has already been decremented whenindex
is calculated so on the first iterationi + 1
is equal toarr.length
in the first function, which is correct.
– Tim Down
Nov 8 '17 at 10:15
add a comment |
A little late to the party but this could be solved with underscore's new sample method (underscore 1.5.2 - Sept 2013):
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var randomFiveNumbers = _.sample(x, 5);
1
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
add a comment |
Or... if you use underscore.js...
_und = require('underscore');
...
function sample(a, n)
return _und.take(_und.shuffle(a), n);
Simple enough.
add a comment |
You can remove the elements from a copy of the array as you select them. Performance is probably not ideal, but it might be OK for what you need:
function getRandom(arr, size)
var copy = arr.slice(0), rand = ;
for (var i = 0; i < size && i < copy.length; i++)
var index = Math.floor(Math.random() * copy.length);
rand.push(copy.splice(index, 1)[0]);
return rand;
add a comment |
While I strongly support using the Fisher-Yates Shuffle, as suggested by Tim Down, here's a very short method for achieving a random subset as requested, mathematically correct, including the empty set, and the given set itself.
Note solution depends on lodash / underscore:
function subset(arr)
return _.sample(arr, _.random(arr.length));
add a comment |
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.
function getRandom(length) return Math.floor(Math.random()*(length));
function getRandomSample(array, size)
var length = array.length;
for(var i = size; i--;)
var index = getRandom(length);
var temp = array[index];
array[index] = array[i];
array[i] = temp;
return array.slice(0, size);
This algorithm is only 2*size
steps, if you include the slice
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.
function getRandomSample(array, size)
var length = array.length, start = getRandom(length);
for(var i = size; i--;)
var index = (start + i)%length, rindex = getRandom(length);
var temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
return 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 the 2*size
.
function getRandomSample(array, size)
var length = array.length, swaps = , i = size, temp;
while(i--)
var rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[i];
array[i] = temp;
swaps.push( from: i, to: rindex );
var sample = array.slice(0, size);
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
No Replacement and More Random
To apply the algorithm that gave a little bit more random samples to the no replacement function:
function getRandomSample(array, size)
var length = array.length, start = getRandom(length),
swaps = , i = size, temp;
while(i--)
var index = (start + i)%length, rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
swaps.push( from: index, to: rindex );
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
Faster...
Like all of these post, this uses the Fisher-Yates Shuffle. But, I removed the over head of copying the array.
function getRandomSample(array, size)
var r, i = array.length, end = i - size, temp, swaps = getRandomSample.swaps;
while (i-- > end)
r = getRandom(i + 1);
temp = array[r];
array[r] = array[i];
array[i] = temp;
swaps.push(i);
swaps.push(r);
var sample = array.slice(end);
while(size--)
i = swaps.pop();
r = swaps.pop();
temp = array[i];
array[i] = array[r];
array[r] = temp;
return sample;
getRandomSample.swaps = ;
add a comment |
If you're using lodash the API changed in 4.x:
const oneItem = _.sample(arr);
const nItems = _.sampleSize(arr, n);
https://lodash.com/docs#sampleSize
add a comment |
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.
function getRandomSample(array, count)
var indices = ;
var result = new Array(count);
for (let i = 0; i < count; i++ )
let j = Math.floor(Math.random() * (array.length - i) + i);
result[i] = array[indices[j] === undefined ? j : indices[j]];
indices[j] = indices[i] === undefined ? i : indices[i];
return result;
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch ofundefined
s in the result.
– Moos
Oct 31 '18 at 23:15
add a comment |
You can get a 5 elements sample by this way:
var sample = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
.map(a => [a,Math.random()])
.sort((a,b) => return a[1] < b[1] ? -1 : 1;)
.slice(0,5)
.map(a => a[0]);
You can define it as a function to use in your code:
var randomSample = function(arr,num) return arr.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]);
Or add it to the Array object itself:
Array.prototype.sample = function(num) return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]); ;
if you want, you can separate the code for to have 2 functionalities (Shuffle and Sample):
Array.prototype.shuffle = function() return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).map(a => a[0]); ;
Array.prototype.sample = function(num) return this.shuffle().slice(0,num); ;
add a comment |
Perhaps I am missing something, but it seems there is a solution that does not require the complexity or potential overhead of a shuffle:
function sample(array,size)
const results = ,
sampled = ;
while(results.length<size && results.length<array.length)
const index = Math.trunc(Math.random() * array.length);
if(!sampled[index])
results.push(array[index]);
sampled[index] = true;
return results;
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f11935175%2fsampling-a-random-subset-from-an-array%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
10 Answers
10
active
oldest
votes
10 Answers
10
active
oldest
votes
active
oldest
votes
active
oldest
votes
I suggest shuffling a copy of the array using the Fisher-Yates shuffle and taking a slice:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(0, size);
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
Note that this will not be the most efficient method for getting a small random subset of a large array because it shuffles the whole array unnecessarily. For better performance you could do a partial shuffle instead:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index;
while (i-- > min)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(min);
1
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
@AaronJo: No, that's deliberate.i
has already been decremented whenindex
is calculated so on the first iterationi + 1
is equal toarr.length
in the first function, which is correct.
– Tim Down
Nov 8 '17 at 10:15
add a comment |
I suggest shuffling a copy of the array using the Fisher-Yates shuffle and taking a slice:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(0, size);
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
Note that this will not be the most efficient method for getting a small random subset of a large array because it shuffles the whole array unnecessarily. For better performance you could do a partial shuffle instead:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index;
while (i-- > min)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(min);
1
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
@AaronJo: No, that's deliberate.i
has already been decremented whenindex
is calculated so on the first iterationi + 1
is equal toarr.length
in the first function, which is correct.
– Tim Down
Nov 8 '17 at 10:15
add a comment |
I suggest shuffling a copy of the array using the Fisher-Yates shuffle and taking a slice:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(0, size);
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
Note that this will not be the most efficient method for getting a small random subset of a large array because it shuffles the whole array unnecessarily. For better performance you could do a partial shuffle instead:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index;
while (i-- > min)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(min);
I suggest shuffling a copy of the array using the Fisher-Yates shuffle and taking a slice:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(0, size);
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
Note that this will not be the most efficient method for getting a small random subset of a large array because it shuffles the whole array unnecessarily. For better performance you could do a partial shuffle instead:
function getRandomSubarray(arr, size)
var shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index;
while (i-- > min)
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
return shuffled.slice(min);
edited Oct 21 '14 at 10:27
answered Aug 13 '12 at 13:30
Tim DownTim Down
252k56380467
252k56380467
1
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
@AaronJo: No, that's deliberate.i
has already been decremented whenindex
is calculated so on the first iterationi + 1
is equal toarr.length
in the first function, which is correct.
– Tim Down
Nov 8 '17 at 10:15
add a comment |
1
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
@AaronJo: No, that's deliberate.i
has already been decremented whenindex
is calculated so on the first iterationi + 1
is equal toarr.length
in the first function, which is correct.
– Tim Down
Nov 8 '17 at 10:15
1
1
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
underscore.js uses a "modern version" of the Fisher-Yates shuffle
– davidDavidson
Feb 17 '16 at 11:28
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
It should be i* Math.random() instead of (i+1) * Math.random(). Math.random() * (i+1) can return i after Math.floor. And arr[i] will result in index out of bound when i==arr.length
– Aaron Jo
Nov 8 '17 at 1:11
@AaronJo: No, that's deliberate.
i
has already been decremented when index
is calculated so on the first iteration i + 1
is equal to arr.length
in the first function, which is correct.– Tim Down
Nov 8 '17 at 10:15
@AaronJo: No, that's deliberate.
i
has already been decremented when index
is calculated so on the first iteration i + 1
is equal to arr.length
in the first function, which is correct.– Tim Down
Nov 8 '17 at 10:15
add a comment |
A little late to the party but this could be solved with underscore's new sample method (underscore 1.5.2 - Sept 2013):
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var randomFiveNumbers = _.sample(x, 5);
1
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
add a comment |
A little late to the party but this could be solved with underscore's new sample method (underscore 1.5.2 - Sept 2013):
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var randomFiveNumbers = _.sample(x, 5);
1
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
add a comment |
A little late to the party but this could be solved with underscore's new sample method (underscore 1.5.2 - Sept 2013):
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var randomFiveNumbers = _.sample(x, 5);
A little late to the party but this could be solved with underscore's new sample method (underscore 1.5.2 - Sept 2013):
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var randomFiveNumbers = _.sample(x, 5);
edited Jun 27 '14 at 6:22
ntalbs
17.9k74670
17.9k74670
answered Oct 28 '13 at 9:27
alengelalengel
1,09611425
1,09611425
1
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
add a comment |
1
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
1
1
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
This produces only 1 element for me, not 5.
– Snowman
Aug 21 '16 at 16:02
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
From underscore's documentation: "Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned." - Did you pass in the second parameter?
– alengel
Aug 22 '16 at 11:18
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
lodash has a _.sampleSize that works as described above: lodash.com/docs/4.17.4#sampleSize
– tonyg
Dec 20 '17 at 17:27
add a comment |
Or... if you use underscore.js...
_und = require('underscore');
...
function sample(a, n)
return _und.take(_und.shuffle(a), n);
Simple enough.
add a comment |
Or... if you use underscore.js...
_und = require('underscore');
...
function sample(a, n)
return _und.take(_und.shuffle(a), n);
Simple enough.
add a comment |
Or... if you use underscore.js...
_und = require('underscore');
...
function sample(a, n)
return _und.take(_und.shuffle(a), n);
Simple enough.
Or... if you use underscore.js...
_und = require('underscore');
...
function sample(a, n)
return _und.take(_und.shuffle(a), n);
Simple enough.
edited Oct 26 '12 at 16:47
Chris Kimpton
4,35364068
4,35364068
answered Aug 13 '12 at 14:26
ntalbsntalbs
17.9k74670
17.9k74670
add a comment |
add a comment |
You can remove the elements from a copy of the array as you select them. Performance is probably not ideal, but it might be OK for what you need:
function getRandom(arr, size)
var copy = arr.slice(0), rand = ;
for (var i = 0; i < size && i < copy.length; i++)
var index = Math.floor(Math.random() * copy.length);
rand.push(copy.splice(index, 1)[0]);
return rand;
add a comment |
You can remove the elements from a copy of the array as you select them. Performance is probably not ideal, but it might be OK for what you need:
function getRandom(arr, size)
var copy = arr.slice(0), rand = ;
for (var i = 0; i < size && i < copy.length; i++)
var index = Math.floor(Math.random() * copy.length);
rand.push(copy.splice(index, 1)[0]);
return rand;
add a comment |
You can remove the elements from a copy of the array as you select them. Performance is probably not ideal, but it might be OK for what you need:
function getRandom(arr, size)
var copy = arr.slice(0), rand = ;
for (var i = 0; i < size && i < copy.length; i++)
var index = Math.floor(Math.random() * copy.length);
rand.push(copy.splice(index, 1)[0]);
return rand;
You can remove the elements from a copy of the array as you select them. Performance is probably not ideal, but it might be OK for what you need:
function getRandom(arr, size)
var copy = arr.slice(0), rand = ;
for (var i = 0; i < size && i < copy.length; i++)
var index = Math.floor(Math.random() * copy.length);
rand.push(copy.splice(index, 1)[0]);
return rand;
answered Aug 13 '12 at 13:41
mamapitufomamapitufo
3,5222018
3,5222018
add a comment |
add a comment |
While I strongly support using the Fisher-Yates Shuffle, as suggested by Tim Down, here's a very short method for achieving a random subset as requested, mathematically correct, including the empty set, and the given set itself.
Note solution depends on lodash / underscore:
function subset(arr)
return _.sample(arr, _.random(arr.length));
add a comment |
While I strongly support using the Fisher-Yates Shuffle, as suggested by Tim Down, here's a very short method for achieving a random subset as requested, mathematically correct, including the empty set, and the given set itself.
Note solution depends on lodash / underscore:
function subset(arr)
return _.sample(arr, _.random(arr.length));
add a comment |
While I strongly support using the Fisher-Yates Shuffle, as suggested by Tim Down, here's a very short method for achieving a random subset as requested, mathematically correct, including the empty set, and the given set itself.
Note solution depends on lodash / underscore:
function subset(arr)
return _.sample(arr, _.random(arr.length));
While I strongly support using the Fisher-Yates Shuffle, as suggested by Tim Down, here's a very short method for achieving a random subset as requested, mathematically correct, including the empty set, and the given set itself.
Note solution depends on lodash / underscore:
function subset(arr)
return _.sample(arr, _.random(arr.length));
edited May 23 '17 at 11:46
Community♦
11
11
answered Jan 11 '15 at 12:41
SelfishSelfish
3,62322449
3,62322449
add a comment |
add a comment |
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.
function getRandom(length) return Math.floor(Math.random()*(length));
function getRandomSample(array, size)
var length = array.length;
for(var i = size; i--;)
var index = getRandom(length);
var temp = array[index];
array[index] = array[i];
array[i] = temp;
return array.slice(0, size);
This algorithm is only 2*size
steps, if you include the slice
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.
function getRandomSample(array, size)
var length = array.length, start = getRandom(length);
for(var i = size; i--;)
var index = (start + i)%length, rindex = getRandom(length);
var temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
return 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 the 2*size
.
function getRandomSample(array, size)
var length = array.length, swaps = , i = size, temp;
while(i--)
var rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[i];
array[i] = temp;
swaps.push( from: i, to: rindex );
var sample = array.slice(0, size);
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
No Replacement and More Random
To apply the algorithm that gave a little bit more random samples to the no replacement function:
function getRandomSample(array, size)
var length = array.length, start = getRandom(length),
swaps = , i = size, temp;
while(i--)
var index = (start + i)%length, rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
swaps.push( from: index, to: rindex );
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
Faster...
Like all of these post, this uses the Fisher-Yates Shuffle. But, I removed the over head of copying the array.
function getRandomSample(array, size)
var r, i = array.length, end = i - size, temp, swaps = getRandomSample.swaps;
while (i-- > end)
r = getRandom(i + 1);
temp = array[r];
array[r] = array[i];
array[i] = temp;
swaps.push(i);
swaps.push(r);
var sample = array.slice(end);
while(size--)
i = swaps.pop();
r = swaps.pop();
temp = array[i];
array[i] = array[r];
array[r] = temp;
return sample;
getRandomSample.swaps = ;
add a comment |
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.
function getRandom(length) return Math.floor(Math.random()*(length));
function getRandomSample(array, size)
var length = array.length;
for(var i = size; i--;)
var index = getRandom(length);
var temp = array[index];
array[index] = array[i];
array[i] = temp;
return array.slice(0, size);
This algorithm is only 2*size
steps, if you include the slice
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.
function getRandomSample(array, size)
var length = array.length, start = getRandom(length);
for(var i = size; i--;)
var index = (start + i)%length, rindex = getRandom(length);
var temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
return 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 the 2*size
.
function getRandomSample(array, size)
var length = array.length, swaps = , i = size, temp;
while(i--)
var rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[i];
array[i] = temp;
swaps.push( from: i, to: rindex );
var sample = array.slice(0, size);
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
No Replacement and More Random
To apply the algorithm that gave a little bit more random samples to the no replacement function:
function getRandomSample(array, size)
var length = array.length, start = getRandom(length),
swaps = , i = size, temp;
while(i--)
var index = (start + i)%length, rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
swaps.push( from: index, to: rindex );
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
Faster...
Like all of these post, this uses the Fisher-Yates Shuffle. But, I removed the over head of copying the array.
function getRandomSample(array, size)
var r, i = array.length, end = i - size, temp, swaps = getRandomSample.swaps;
while (i-- > end)
r = getRandom(i + 1);
temp = array[r];
array[r] = array[i];
array[i] = temp;
swaps.push(i);
swaps.push(r);
var sample = array.slice(end);
while(size--)
i = swaps.pop();
r = swaps.pop();
temp = array[i];
array[i] = array[r];
array[r] = temp;
return sample;
getRandomSample.swaps = ;
add a comment |
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.
function getRandom(length) return Math.floor(Math.random()*(length));
function getRandomSample(array, size)
var length = array.length;
for(var i = size; i--;)
var index = getRandom(length);
var temp = array[index];
array[index] = array[i];
array[i] = temp;
return array.slice(0, size);
This algorithm is only 2*size
steps, if you include the slice
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.
function getRandomSample(array, size)
var length = array.length, start = getRandom(length);
for(var i = size; i--;)
var index = (start + i)%length, rindex = getRandom(length);
var temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
return 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 the 2*size
.
function getRandomSample(array, size)
var length = array.length, swaps = , i = size, temp;
while(i--)
var rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[i];
array[i] = temp;
swaps.push( from: i, to: rindex );
var sample = array.slice(0, size);
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
No Replacement and More Random
To apply the algorithm that gave a little bit more random samples to the no replacement function:
function getRandomSample(array, size)
var length = array.length, start = getRandom(length),
swaps = , i = size, temp;
while(i--)
var index = (start + i)%length, rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
swaps.push( from: index, to: rindex );
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
Faster...
Like all of these post, this uses the Fisher-Yates Shuffle. But, I removed the over head of copying the array.
function getRandomSample(array, size)
var r, i = array.length, end = i - size, temp, swaps = getRandomSample.swaps;
while (i-- > end)
r = getRandom(i + 1);
temp = array[r];
array[r] = array[i];
array[i] = temp;
swaps.push(i);
swaps.push(r);
var sample = array.slice(end);
while(size--)
i = swaps.pop();
r = swaps.pop();
temp = array[i];
array[i] = array[r];
array[r] = temp;
return sample;
getRandomSample.swaps = ;
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.
function getRandom(length) return Math.floor(Math.random()*(length));
function getRandomSample(array, size)
var length = array.length;
for(var i = size; i--;)
var index = getRandom(length);
var temp = array[index];
array[index] = array[i];
array[i] = temp;
return array.slice(0, size);
This algorithm is only 2*size
steps, if you include the slice
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.
function getRandomSample(array, size)
var length = array.length, start = getRandom(length);
for(var i = size; i--;)
var index = (start + i)%length, rindex = getRandom(length);
var temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
return 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 the 2*size
.
function getRandomSample(array, size)
var length = array.length, swaps = , i = size, temp;
while(i--)
var rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[i];
array[i] = temp;
swaps.push( from: i, to: rindex );
var sample = array.slice(0, size);
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
No Replacement and More Random
To apply the algorithm that gave a little bit more random samples to the no replacement function:
function getRandomSample(array, size)
var length = array.length, start = getRandom(length),
swaps = , i = size, temp;
while(i--)
var index = (start + i)%length, rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
swaps.push( from: index, to: rindex );
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
// Put everything back.
i = size;
while(i--)
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
return sample;
Faster...
Like all of these post, this uses the Fisher-Yates Shuffle. But, I removed the over head of copying the array.
function getRandomSample(array, size)
var r, i = array.length, end = i - size, temp, swaps = getRandomSample.swaps;
while (i-- > end)
r = getRandom(i + 1);
temp = array[r];
array[r] = array[i];
array[i] = temp;
swaps.push(i);
swaps.push(r);
var sample = array.slice(end);
while(size--)
i = swaps.pop();
r = swaps.pop();
temp = array[i];
array[i] = array[r];
array[r] = temp;
return sample;
getRandomSample.swaps = ;
edited Jun 17 '16 at 15:51
answered Jun 15 '16 at 12:37
tkellehetkellehe
52639
52639
add a comment |
add a comment |
If you're using lodash the API changed in 4.x:
const oneItem = _.sample(arr);
const nItems = _.sampleSize(arr, n);
https://lodash.com/docs#sampleSize
add a comment |
If you're using lodash the API changed in 4.x:
const oneItem = _.sample(arr);
const nItems = _.sampleSize(arr, n);
https://lodash.com/docs#sampleSize
add a comment |
If you're using lodash the API changed in 4.x:
const oneItem = _.sample(arr);
const nItems = _.sampleSize(arr, n);
https://lodash.com/docs#sampleSize
If you're using lodash the API changed in 4.x:
const oneItem = _.sample(arr);
const nItems = _.sampleSize(arr, n);
https://lodash.com/docs#sampleSize
answered Aug 27 '16 at 21:02
chovychovy
36k32157213
36k32157213
add a comment |
add a comment |
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.
function getRandomSample(array, count)
var indices = ;
var result = new Array(count);
for (let i = 0; i < count; i++ )
let j = Math.floor(Math.random() * (array.length - i) + i);
result[i] = array[indices[j] === undefined ? j : indices[j]];
indices[j] = indices[i] === undefined ? i : indices[i];
return result;
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch ofundefined
s in the result.
– Moos
Oct 31 '18 at 23:15
add a comment |
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.
function getRandomSample(array, count)
var indices = ;
var result = new Array(count);
for (let i = 0; i < count; i++ )
let j = Math.floor(Math.random() * (array.length - i) + i);
result[i] = array[indices[j] === undefined ? j : indices[j]];
indices[j] = indices[i] === undefined ? i : indices[i];
return result;
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch ofundefined
s in the result.
– Moos
Oct 31 '18 at 23:15
add a comment |
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.
function getRandomSample(array, count)
var indices = ;
var result = new Array(count);
for (let i = 0; i < count; i++ )
let j = Math.floor(Math.random() * (array.length - i) + i);
result[i] = array[indices[j] === undefined ? j : indices[j]];
indices[j] = indices[i] === undefined ? i : indices[i];
return result;
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.
function getRandomSample(array, count)
var indices = ;
var result = new Array(count);
for (let i = 0; i < count; i++ )
let j = Math.floor(Math.random() * (array.length - i) + i);
result[i] = array[indices[j] === undefined ? j : indices[j]];
indices[j] = indices[i] === undefined ? i : indices[i];
return result;
answered Jun 15 '16 at 11:31
Jesús LópezJesús López
4,23411442
4,23411442
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch ofundefined
s in the result.
– Moos
Oct 31 '18 at 23:15
add a comment |
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch ofundefined
s in the result.
– Moos
Oct 31 '18 at 23:15
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch of
undefined
s in the result.– Moos
Oct 31 '18 at 23:15
I don't how this works, but it does -- and it's much more efficient when count << array.length. To make it completely generic (i.e., when count is equal or greater than array length) I added: ` let val = array[indices[j] === undefined ? j : indices[j]]; if (val === undefined) result.length = i; break; result[i] = val; ` to force result.length <= array.length, otherwise will get bunch of
undefined
s in the result.– Moos
Oct 31 '18 at 23:15
add a comment |
You can get a 5 elements sample by this way:
var sample = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
.map(a => [a,Math.random()])
.sort((a,b) => return a[1] < b[1] ? -1 : 1;)
.slice(0,5)
.map(a => a[0]);
You can define it as a function to use in your code:
var randomSample = function(arr,num) return arr.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]);
Or add it to the Array object itself:
Array.prototype.sample = function(num) return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]); ;
if you want, you can separate the code for to have 2 functionalities (Shuffle and Sample):
Array.prototype.shuffle = function() return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).map(a => a[0]); ;
Array.prototype.sample = function(num) return this.shuffle().slice(0,num); ;
add a comment |
You can get a 5 elements sample by this way:
var sample = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
.map(a => [a,Math.random()])
.sort((a,b) => return a[1] < b[1] ? -1 : 1;)
.slice(0,5)
.map(a => a[0]);
You can define it as a function to use in your code:
var randomSample = function(arr,num) return arr.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]);
Or add it to the Array object itself:
Array.prototype.sample = function(num) return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]); ;
if you want, you can separate the code for to have 2 functionalities (Shuffle and Sample):
Array.prototype.shuffle = function() return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).map(a => a[0]); ;
Array.prototype.sample = function(num) return this.shuffle().slice(0,num); ;
add a comment |
You can get a 5 elements sample by this way:
var sample = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
.map(a => [a,Math.random()])
.sort((a,b) => return a[1] < b[1] ? -1 : 1;)
.slice(0,5)
.map(a => a[0]);
You can define it as a function to use in your code:
var randomSample = function(arr,num) return arr.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]);
Or add it to the Array object itself:
Array.prototype.sample = function(num) return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]); ;
if you want, you can separate the code for to have 2 functionalities (Shuffle and Sample):
Array.prototype.shuffle = function() return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).map(a => a[0]); ;
Array.prototype.sample = function(num) return this.shuffle().slice(0,num); ;
You can get a 5 elements sample by this way:
var sample = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
.map(a => [a,Math.random()])
.sort((a,b) => return a[1] < b[1] ? -1 : 1;)
.slice(0,5)
.map(a => a[0]);
You can define it as a function to use in your code:
var randomSample = function(arr,num) return arr.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]);
Or add it to the Array object itself:
Array.prototype.sample = function(num) return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).slice(0,num).map(a => a[0]); ;
if you want, you can separate the code for to have 2 functionalities (Shuffle and Sample):
Array.prototype.shuffle = function() return this.map(a => [a,Math.random()]).sort((a,b) => return a[1] < b[1] ? -1 : 1;).map(a => a[0]); ;
Array.prototype.sample = function(num) return this.shuffle().slice(0,num); ;
answered Sep 8 '18 at 7:12
Luis MarinLuis Marin
112
112
add a comment |
add a comment |
Perhaps I am missing something, but it seems there is a solution that does not require the complexity or potential overhead of a shuffle:
function sample(array,size)
const results = ,
sampled = ;
while(results.length<size && results.length<array.length)
const index = Math.trunc(Math.random() * array.length);
if(!sampled[index])
results.push(array[index]);
sampled[index] = true;
return results;
add a comment |
Perhaps I am missing something, but it seems there is a solution that does not require the complexity or potential overhead of a shuffle:
function sample(array,size)
const results = ,
sampled = ;
while(results.length<size && results.length<array.length)
const index = Math.trunc(Math.random() * array.length);
if(!sampled[index])
results.push(array[index]);
sampled[index] = true;
return results;
add a comment |
Perhaps I am missing something, but it seems there is a solution that does not require the complexity or potential overhead of a shuffle:
function sample(array,size)
const results = ,
sampled = ;
while(results.length<size && results.length<array.length)
const index = Math.trunc(Math.random() * array.length);
if(!sampled[index])
results.push(array[index]);
sampled[index] = true;
return results;
Perhaps I am missing something, but it seems there is a solution that does not require the complexity or potential overhead of a shuffle:
function sample(array,size)
const results = ,
sampled = ;
while(results.length<size && results.length<array.length)
const index = Math.trunc(Math.random() * array.length);
if(!sampled[index])
results.push(array[index]);
sampled[index] = true;
return results;
answered Jan 12 at 14:32
AnyWhichWayAnyWhichWay
13227
13227
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f11935175%2fsampling-a-random-subset-from-an-array%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I noticed Avi Moondra's bl.ock uses this technique
– The Red Pea
Aug 27 '16 at 3:36