192

I am working on 'how to access elements randomly from an array in javascript'. I found many links regarding this. Like: Get random item from JavaScript array

var item = items[Math.floor(Math.random()*items.length)];

But in this, we can choose only one item from the array. If we want more than one elements then how can we achieve this? How can we get more than one element from an array?

Dharman
  • 30,962
  • 25
  • 85
  • 135
Shyam Dixit
  • 2,325
  • 3
  • 19
  • 27
  • 7
    Just execute it multiple times? – Bergi Oct 09 '13 at 10:33
  • 4
    From this statement can we do this?? Loop generating duplicates. – Shyam Dixit Oct 09 '13 at 10:35
  • 1
    From that exact statement you can't get more than one element. – Sébastien Oct 09 '13 at 10:35
  • 2
    Ah, you should've said that you want no duplicates. Then check [Unique random numbers in O(1)?](http://stackoverflow.com/questions/196017/unique-random-numbers-in-o1) and my answer at [Generate unique number within range (0 - X), keeping a history to prevent duplicates](http://stackoverflow.com/questions/11808804/generate-unique-number-within-range-0-x-keeping-a-history-to-prevent-duplic) – Bergi Oct 09 '13 at 10:40
  • shuffle the array and get the first N, see http://stackoverflow.com/q/2450954/989121 – georg Oct 09 '13 at 10:59
  • 1
    I made a JsPerf to test some of the solutions here. @Bergi's seems to be the best in general, while mine works better if you need many elements from the array. http://jsperf.com/k-random-elements-from-array – Tibos Oct 09 '13 at 14:20

26 Answers26

332

Just two lines :

// Shuffle array
const shuffled = array.sort(() => 0.5 - Math.random());

// Get sub-array of first n elements after shuffled
let selected = shuffled.slice(0, n);

DEMO:

Community
  • 1
  • 1
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
210

Try this non-destructive (and fast) function:

function getRandom(arr, n) {
    var result = new Array(n),
        len = arr.length,
        taken = new Array(len);
    if (n > len)
        throw new RangeError("getRandom: more elements taken than available");
    while (n--) {
        var x = Math.floor(Math.random() * len);
        result[n] = arr[x in taken ? taken[x] : x];
        taken[x] = --len in taken ? taken[len] : len;
    }
    return result;
}
I wrestled a bear once.
  • 22,983
  • 19
  • 69
  • 116
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 44
    Hey man, I just wanted to say I spent about ten minutes appreciating the beauty of this algorithm. – Prajeeth Emanuel Apr 08 '17 at 09:57
  • @Derek朕會功夫 Ah, clever, that works much better for small samples from large ranges indeed. Especially with using an ES6 `Set` (which wasn't available in '13 :-/) – Bergi Aug 08 '17 at 00:22
  • @AlexWhite Thanks for the feedback, I can't believe this bug evaded everyone for years. Fixed. You should have posted a comment though, not suggested an edit. – Bergi Feb 20 '18 at 17:22
  • @Bergi this is mind bending. Can I be sure that it won't select the same item more than one time? Thanks! – cbdeveloper Sep 24 '19 at 09:09
  • 2
    @cbdev420 Yes, it's just a (partial) fisher-yates shuffle – Bergi Sep 24 '19 at 12:52
  • I'm trying to wrap my head around how this implementation would not yield duplicates. The comments seem to indicate that it *would* and then it *wouldn't*. But, looking at the code, I don't see how it would prevent duplicates. What am I missing? – robross0606 Apr 06 '20 at 14:20
  • @robross0606 I'm confused by those old comments as well, I've flagged them to be removed. This answer definitely does not produce duplicates (or, only if the input `arr` did contain some), by keeping track of the indices that already were taken. "*Editing the question now would invalidate the answers*" refers to other answers, like the one by Laurynas. – Bergi Apr 06 '20 at 15:06
  • @Bergi I wonder how a predicate could be worked into that? So that one could say "I don't want to have a particular item to be included in the result array`. And also protect against an infinite loop over len when all selected elements being rejected by the predicate. – philk May 28 '20 at 12:08
  • @philk Just don't include that particular item in the array that you pass? `getRandom(items.filter(…), …)` – Bergi May 28 '20 at 14:05
  • the problem with this method is that it will get increasingly slow, and in the end it could get slower than just removing the elements you pick – Martijn Scheffer Apr 15 '21 at 13:04
  • @MartijnScheffer No, it doesn't get slower, it gives you `n` elements in `O(n)` bounded time – Bergi Apr 15 '21 at 13:22
  • 1
    The jsPerf link seems broken at the moment. – KeshavDulal Jun 22 '21 at 14:43
  • @KeshavDulal - jsPerf has been offline for a long time. This answer is nearly a decade old. – I wrestled a bear once. Jul 23 '21 at 17:14
34

There is a one-liner unique solution here

 array.sort(() => Math.random() - Math.random()).slice(0, n)
Olalekan Sogunle
  • 2,299
  • 1
  • 20
  • 26
25

lodash _.sample and _.sampleSize.

Gets one or n random elements at unique keys from collection up to the size of collection.

_.sample([1, 2, 3, 4]);
// => 2

_.sampleSize([1, 2, 3], 2);
// => [3, 1]
 
_.sampleSize([1, 2, 3], 3);
// => [2, 3, 1]
genericUser
  • 4,417
  • 1
  • 28
  • 73
nodejh
  • 7,928
  • 1
  • 20
  • 24
15

Getting 5 random items without changing the original array:

const n = 5;
const sample = items
  .map(x => ({ x, r: Math.random() }))
  .sort((a, b) => a.r - b.r)
  .map(a => a.x)
  .slice(0, n);

(Don't use this for big lists)

pomber
  • 23,132
  • 10
  • 81
  • 94
  • Could we have a better explanation of how this works? – Qasim Jan 01 '20 at 07:28
  • @Qasim, the algorithm takes an array of `items` (line 2) and makes an array of pairs: the original item and a random number (line 3). It then sorts the array of pairs per the random number (line 4). Then it makes a list of simple items again, only using the original item (thus skipping the random number, line 5). Finally, it picks the first `n` items of the (randomly ordered) array of items (line 6). For a better understanding, read the documentation of functions like `map` and `sort`, like in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map. – Jochem Schulenklopper Mar 26 '21 at 17:48
14

Porting .sample from the Python standard library:

function sample(population, k){
    /*
        Chooses k unique random elements from a population sequence or set.

        Returns a new list containing elements from the population while
        leaving the original population unchanged.  The resulting list is
        in selection order so that all sub-slices will also be valid random
        samples.  This allows raffle winners (the sample) to be partitioned
        into grand prize and second place winners (the subslices).

        Members of the population need not be hashable or unique.  If the
        population contains repeats, then each occurrence is a possible
        selection in the sample.

        To choose a sample in a range of integers, use range as an argument.
        This is especially fast and space efficient for sampling from a
        large population:   sample(range(10000000), 60)

        Sampling without replacement entails tracking either potential
        selections (the pool) in a list or previous selections in a set.

        When the number of selections is small compared to the
        population, then tracking selections is efficient, requiring
        only a small set and an occasional reselection.  For
        a larger number of selections, the pool tracking method is
        preferred since the list takes less space than the
        set and it doesn't suffer from frequent reselections.
    */

    if(!Array.isArray(population))
        throw new TypeError("Population must be an array.");
    var n = population.length;
    if(k < 0 || k > n)
        throw new RangeError("Sample larger than population or is negative");

    var result = new Array(k);
    var setsize = 21;   // size of a small set minus size of an empty list

    if(k > 5)
        setsize += Math.pow(4, Math.ceil(Math.log(k * 3) / Math.log(4)))

    if(n <= setsize){
        // An n-length list is smaller than a k-length set
        var pool = population.slice();
        for(var i = 0; i < k; i++){          // invariant:  non-selected at [0,n-i)
            var j = Math.random() * (n - i) | 0;
            result[i] = pool[j];
            pool[j] = pool[n - i - 1];       // move non-selected item into vacancy
        }
    }else{
        var selected = new Set();
        for(var i = 0; i < k; i++){
            var j = Math.random() * n | 0;
            while(selected.has(j)){
                j = Math.random() * n | 0;
            }
            selected.add(j);
            result[i] = population[j];
        }
    }

    return result;
}

Implementation ported from Lib/random.py.

Notes:

  • setsize is set based on characteristics in Python for efficiency. Although it has not been adjusted for JavaScript, the algorithm will still function as expected.
  • Some other answers described in this page are not safe according to the ECMAScript specification due to the misuse of Array.prototype.sort. This algorithm however is guaranteed to terminate in finite time.
  • For older browsers that do not have Set implemented, the set can be replaced with an Array and .has(j) replaced with .indexOf(j) > -1.

Performance against the accepted answer:

user
  • 23,260
  • 9
  • 113
  • 101
Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • I've posted an [optimized version](https://stackoverflow.com/a/61078260/3075942) of this code below. Also corrected the wrong random parameter in the second algo in your post. I wonder how many people are using the previous biased version in production, hope nothing critical. – user Apr 07 '20 at 11:35
13

create a funcion which does that:

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
        result.push(sourceArray[Math.floor(Math.random()*sourceArray.length)]);
    }
    return result;
}

you should also check if the sourceArray has enough elements to be returned. and if you want unique elements returned, you should remove selected element from the sourceArray.

Laurynas Mališauskas
  • 1,909
  • 1
  • 19
  • 34
11

If you want to randomly get items from the array in a loop without repetitions you can remove the selected item from the array with splice:

var items = [1, 2, 3, 4, 5];
var newItems = [];

for (var i = 0; i < 3; i++) {
  var idx = Math.floor(Math.random() * items.length);
  newItems.push(items[idx]);
  items.splice(idx, 1);
}

console.log(newItems);
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • 1
    In statement items.splice(idx,1) why you use this '1'? splice?? – Shyam Dixit Oct 09 '13 at 10:47
  • 2
    [Shyam Dixit](https://stackoverflow.com/users/2484788/shyam-dixit), according to the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) the `1` is the `deleteCount` indicating the number of old array elements to remove. (Incidentally, I reduced the last two lines to `newItems.push(items.splice(idx, 1)[0])`). – Kurt Peek Oct 10 '17 at 07:14
7

ES6 syntax

const pickRandom = (arr,count) => {
  let _arr = [...arr];
  return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] ); 
}
Yair Levy
  • 1,354
  • 16
  • 12
5

I can't believe that no one didn't mention this method, pretty clean and straightforward.

const getRnd = (a, n) => new Array(n).fill(null).map(() => a[Math.floor(Math.random() * a.length)]);
DedaDev
  • 4,441
  • 2
  • 21
  • 28
3
Array.prototype.getnkill = function() {
    var a = Math.floor(Math.random()*this.length);
    var dead = this[a];
    this.splice(a,1);
    return dead;
}

//.getnkill() removes element in the array 
//so if you like you can keep a copy of the array first:

//var original= items.slice(0); 


var item = items.getnkill();

var anotheritem = items.getnkill();
Archy Will He 何魏奇
  • 9,589
  • 4
  • 34
  • 50
3

Here's a nicely typed version. It doesn't fail. Returns a shuffled array if sample size is larger than original array's length.

function sampleArr<T>(arr: T[], size: number): T[] {
  const setOfIndexes = new Set<number>();
  while (setOfIndexes.size < size && setOfIndexes.size < arr.length) {
    setOfIndexes.add(randomIntFromInterval(0, arr.length - 1));
  }
  return Array.from(setOfIndexes.values()).map(i => arr[i]);
}

const randomIntFromInterval = (min: number, max: number): number =>
  Math.floor(Math.random() * (max - min + 1) + min);
Daniel Birowsky Popeski
  • 8,752
  • 12
  • 60
  • 125
3

In this answer, I want to share with you the test that I have to know the best method that gives equal chances for all elements to have random subarray.

Method 01

array.sort(() => Math.random() - Math.random()).slice(0, n)

using this method, some elements have higher chances comparing with others.

calculateProbability = function(number=0 ,iterations=10000,arraySize=100) { 
let occ = 0 
for (let index = 0; index < iterations; index++) {
   const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize]
   
  /** Wrong Method */
    const arr = myArray.sort(function() {
     return val= .5 - Math.random();
      });
     
  if(arr[0]===number) {
    occ ++
    }

    
}

console.log("Probability of ",number, " = ",occ*100 /iterations,"%")

}

calculateProbability(0)
calculateProbability(0)
calculateProbability(0)
calculateProbability(50)
calculateProbability(50)
calculateProbability(50)
calculateProbability(25)
calculateProbability(25)
calculateProbability(25)

Method 2

Using this method, the elements have the same probability:

 const arr = myArray
      .map((a) => ({sort: Math.random(), value: a}))
      .sort((a, b) => a.sort - b.sort)
      .map((a) => a.value)

calculateProbability = function(number=0 ,iterations=10000,arraySize=100) { 
let occ = 0 
for (let index = 0; index < iterations; index++) {
   const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize]
   

  /** Correct Method */
  const arr = myArray
  .map((a) => ({sort: Math.random(), value: a}))
  .sort((a, b) => a.sort - b.sort)
  .map((a) => a.value)
    
  if(arr[0]===number) {
    occ ++
    }

    
}

console.log("Probability of ",number, " = ",occ*100 /iterations,"%")

}

calculateProbability(0)
calculateProbability(0)
calculateProbability(0)
calculateProbability(50)
calculateProbability(50)
calculateProbability(50)
calculateProbability(25)
calculateProbability(25)
calculateProbability(25)

The correct answer is posted in in the following link: https://stackoverflow.com/a/46545530/3811640

haouarin
  • 1,511
  • 1
  • 11
  • 8
3

2020
non destructive functional programing style, working in a immutable context.

const _randomslice = (ar, size) => {
  let new_ar = [...ar];
  new_ar.splice(Math.floor(Math.random()*ar.length),1);
  return ar.length <= (size+1) ? new_ar : _randomslice(new_ar, size);
}


console.log(_randomslice([1,2,3,4,5],2));
1

EDIT: This solution is slower than others presented here (which splice the source array) if you want to get only a few elements. The speed of this solution depends only on the number of elements in the original array, while the speed of the splicing solution depends on the number of elements required in the output array.

If you want non-repeating random elements, you can shuffle your array then get only as many as you want:

function shuffle(array) {
    var counter = array.length, temp, index;

    // While there are elements in the array
    while (counter--) {
        // Pick a random index
        index = (Math.random() * counter) | 0;

        // And swap the last element with it
        temp = array[counter];
        array[counter] = array[index];
        array[index] = temp;
    }

    return array;
}

var arr = [0,1,2,3,4,5,7,8,9];

var randoms = shuffle(arr.slice(0)); // array is cloned so it won't be destroyed
randoms.length = 4; // get 4 random elements

DEMO: http://jsbin.com/UHUHuqi/1/edit

Shuffle function taken from here: https://stackoverflow.com/a/6274398/1669279

Community
  • 1
  • 1
Tibos
  • 27,507
  • 4
  • 50
  • 64
  • That depends on the percentage of random items required from the array. If you want 9 random elements from a 10 element array, it will surely be faster to shuffle than to extract 9 random elements one after the other. If the percentage this is useful for is less than 50%, then there are use cases where this solution is the fastest. Otherwise i concede that it is useless :). – Tibos Oct 09 '13 at 10:52
  • I meant that shuffling 9 elements is faster than shuffling 10 elements. Btw I'm confident that the OP does not want to destroy his input array… – Bergi Oct 09 '13 at 10:59
  • I don't think i understand how shuffling 9 elements helps in this problem. I am aware that if you want more than half the array you can simply slice-out random elements until you remain with how many you want then shuffle to get a random order. Is there anything i missed? PS: Fixed array destruction, thanks. – Tibos Oct 09 '13 at 11:12
  • It doesn't have to do anything with "half of". You just need to do as much work as elements you want to get back, you don't need to treat the whole array at any point. Your current code has a complexity of `O(n+k)` (n elements in the array, you want k of them) while `O(k)` would be possible (and optimal). – Bergi Oct 09 '13 at 11:44
  • This is turning into a lengthy discussion :). I think you are mistaken about the complexities. My code has a complexity of O(n). Splicing code (ex:Rory's McCrossan's answer) has a complexity of O(k), but that is not taking into account splicing which can be very expensive (a naive implementation of splicing would get a O(n) complexity for it. I made a JsPerf to test it for a situation i expect shuffling to be better, available here: http://jsperf.com/k-random-elements-from-array. Feel free to edit it with a better example! – Tibos Oct 09 '13 at 12:01
  • 1
    OK, your code has more like `O(2n)` which could be reduced to `O(n+k)` if you'd change the loop to `while (counter-- > len-k)` and take the last (instead of first) `k` elements out of it. Indeed `splice(i, 1)` doesn't have `O(1)`, but a `O(k)` solution is still possible (see my answer). Space complexity however stays at `O(n+k)` unfortunately, but could become `O(2k)` depending on the sparse array implementation. – Bergi Oct 09 '13 at 12:24
1

I needed a function to solve this kind of issue so I'm sharing it here.

    const getRandomItem = function(arr) {
        return arr[Math.floor(Math.random() * arr.length)];
    }

    // original array
    let arr = [4, 3, 1, 6, 9, 8, 5];

    // number of random elements to get from arr
    let n = 4;

    let count = 0;
    // new array to push random item in
    let randomItems = []
    do {
        let item = getRandomItem(arr);
        randomItems.push(item);
        // update the original array and remove the recently pushed item
        arr.splice(arr.indexOf(item), 1);
        count++;
    } while(count < n);

    console.log(randomItems);
    console.log(arr);

Note: if n = arr.length then basically you're shuffling the array arr and randomItems returns that shuffled array.

Demo

Storage Lenovo
  • 85
  • 1
  • 1
  • 6
1

Here's an optimized version of the code ported from Python by @Derek, with the added destructive (in-place) option that makes it the fastest algorithm possible if you can go with it. Otherwise it either makes a full copy or, for a small number of items requested from a large array, switches to a selection-based algorithm.

// Chooses k unique random elements from pool.
function sample(pool, k, destructive) {
    var n = pool.length;
    
    if (k < 0 || k > n)
        throw new RangeError("Sample larger than population or is negative");
    
    if (destructive || n <= (k <= 5 ? 21 : 21 + Math.pow(4, Math.ceil(Math.log(k*3) / Math.log(4))))) {
        if (!destructive)
            pool = Array.prototype.slice.call(pool);
        for (var i = 0; i < k; i++) { // invariant: non-selected at [i,n)
            var j = i + Math.random() * (n - i) | 0;
            var x = pool[i];
            pool[i] = pool[j];
            pool[j] = x;
        }
        pool.length = k; // truncate
        return pool;
    } else {
        var selected = new Set();
        while (selected.add(Math.random() * n | 0).size < k) {}
        return Array.prototype.map.call(selected, i => pool[i]);
    }
}

In comparison to Derek's implementation, the first algorithm is much faster in Firefox while being a bit slower in Chrome, although now it has the destructive option - the most performant one. The second algorithm is simply 5-15% faster. I try not to give any concrete numbers since they vary depending on k and n and probably won't mean anything in the future with the new browser versions.

The heuristic that makes the choice between algorithms originates from Python code. I've left it as is, although it sometimes selects the slower one. It should be optimized for JS, but it's a complex task since the performance of corner cases is browser- and their version-dependent. For example, when you try to select 20 out of 1000 or 1050, it will switch to the first or the second algorithm accordingly. In this case the first one runs 2x faster than the second one in Chrome 80 but 3x slower in Firefox 74.

user
  • 23,260
  • 9
  • 113
  • 101
  • There's an error in `log(k*3, 4)` since JS doesn't have the `base` argument. Should be `log(k*3)/log(4)` – disfated Sep 28 '20 at 14:49
  • Also, I see a downside in the part where you reuse `pool` as a `result`. Since you truncate `pool` it cannot be used as a source for sampling any longer and next time you use `sample` you will have to recreate `pool` from some source again. Derek's implementation only shuffles the pool, so it can be perfectly reused for sampling without recreating. And I believe this is the most frequent use case. – disfated Sep 28 '20 at 15:44
  • @disfated, thanks, fixed `log` in my and Derek's code. As for reusing the `pool`, just don't enable the `destructive` option, then the `pool` argument is shadowed with a copy. – user Nov 28 '20 at 08:58
1

Sampling with possible duplicates:

const sample_with_duplicates = Array(sample_size).fill().map(() => items[~~(Math.random() * items.length)])

Sampling without duplicates:

const sample_without_duplicates = [...Array(items.length).keys()].sort(() => 0.5 - Math.random()).slice(0, sample_size).map(index => items[index]);

Since without duplicates requires sorting the whole index array first, it is considerably slow than with possible duplicates for big items input arrays.

Obviously, the max size of without duplicates is <= items.length

Check this fiddle: https://jsfiddle.net/doleron/5zw2vequ/30/

Duloren
  • 2,395
  • 1
  • 25
  • 36
  • This is a simple solution for simple cases, but for large arrays, it's not truly random. I suggest using `Fisher-Yates (aka Knuth) Shuffle` and then you should cut first N results with the `slice`. – joe.kovalski Apr 15 '22 at 14:32
0

It extracts random elements from srcArray one by one while it get's enough or there is no more elements in srcArray left for extracting. Fast and reliable.

function getNRandomValuesFromArray(srcArr, n) {
    // making copy to do not affect original srcArray
    srcArr = srcArr.slice();
    resultArr = [];
    // while srcArray isn't empty AND we didn't enough random elements
    while (srcArr.length && resultArr.length < n) {
        // remove one element from random position and add this element to the result array
        resultArr = resultArr.concat( // merge arrays
            srcArr.splice( // extract one random element
                Math.floor(Math.random() * srcArr.length),
                1
            )
        );
    }

    return resultArr;
}
Armalong
  • 101
  • 1
  • 4
  • Welcome to SO! When posting answers, it is important to mention how your code works and/or how it solves OP's problem :) – Joel Aug 30 '18 at 18:05
0

2019

This is same as Laurynas Mališauskas answer, just that the elements are unique (no duplicates).

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
    var index = Math.floor(Math.random() * sourceArray.length);
        result.push(sourceArray[index]);
        sourceArray.splice(index, 1);
    }
    return result;
}

Now to answer original question "How to get multiple random elements by jQuery", here you go:

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
    var index = Math.floor(Math.random() * sourceArray.length);
        result.push(sourceArray[index]);
        sourceArray.splice(index, 1);
    }
    return result;
}

var $set = $('.someClass');// <<<<< change this please

var allIndexes = [];
for(var i = 0; i < $set.length; ++i) {
    allIndexes.push(i);
}

var totalRandom = 4;// <<<<< change this please
var randomIndexes = getMeRandomElements(allIndexes, totalRandom);

var $randomElements = null;
for(var i = 0; i < randomIndexes.length; ++i) {
    var randomIndex = randomIndexes[i];
    if($randomElements === null) {
        $randomElements = $set.eq(randomIndex);
    } else {
        $randomElements.add($set.eq(randomIndex));
    }
}

// $randomElements is ready
$randomElements.css('backgroundColor', 'red');
evilReiko
  • 19,501
  • 24
  • 86
  • 102
0

Here's a function I use that allows you to easily sample an array with or without replacement:

  // Returns a random sample (either with or without replacement) from an array
  const randomSample = (arr, k, withReplacement = false) => {
    let sample;
    if (withReplacement === true) {  // sample with replacement
      sample = Array.from({length: k}, () => arr[Math.floor(Math.random() *  arr.length)]);
    } else { // sample without replacement
      if (k > arr.length) {
        throw new RangeError('Sample size must be less than or equal to array length         when sampling without replacement.')
      }
      sample = arr.map(a => [a, Math.random()]).sort((a, b) => {
        return a[1] < b[1] ? -1 : 1;}).slice(0, k).map(a => a[0]); 
      };
    return sample;
  };

Using it is simple:

Without Replacement (default behavior)

randomSample([1, 2, 3], 2) may return [2, 1]

With Replacement

randomSample([1, 2, 3, 4, 5, 6], 4) may return [2, 3, 3, 2]

Jared Wilber
  • 6,038
  • 1
  • 32
  • 35
0
var getRandomElements = function(sourceArray, requiredLength) {
    var result = [];
    while(result.length<requiredLength){
        random = Math.floor(Math.random()*sourceArray.length);
        if(result.indexOf(sourceArray[random])==-1){
            result.push(sourceArray[random]);
        }
    }
    return result;
}
Manoj Rana
  • 3,068
  • 1
  • 24
  • 34
0
const items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1, 2, 3, 4, 5];

const fetchRandomArray = ({pool=[], limit=1})=>{
let query = []
let selectedIndices = {}

while(query.length < limit){
    const index = Math.floor(Math.random()*pool.length)
    if(typeof(selectedIndices[index])==='undefined'){
        query.push(items[index])
        selectedIndices[index] = index
    }
}

console.log(fetchRandomArray({pool:items, limit:10})
0

you actually don't need to sort, you only have to generate a random subarray length:

const myArray = ["January", "February", "March", "April", "May", "June", "July"];

const randomNumGenerator = () => Math.floor(Math.random() * myArray.length)

const result = [
  ...new Set(
    Array.from({
        length: randomNumGenerator() + 1
      },
      _ => myArray[randomNumGenerator()])
  )
]

console.log(result)
Alan Omar
  • 4,023
  • 1
  • 9
  • 20
-2

Here is the most correct answer and it will give you Random + Unique elements.

function randomize(array, n)
{
    var final = [];
    array = array.filter(function(elem, index, self) {
        return index == self.indexOf(elem);
    }).sort(function() { return 0.5 - Math.random() });

    var len = array.length,
    n = n > len ? len : n;

    for(var i = 0; i < n; i ++)
    {
        final[i] = array[i];
    }

    return final;
}

// randomize([1,2,3,4,5,3,2], 4);
// Result: [1, 2, 3, 5] // Something like this
Nivesh Saharan
  • 365
  • 3
  • 11
  • There's something strange going on with the randomization in this one - I had the same result show up 6 out of 9 tries (with an n of 8 and an array size of 148). You might think about switching to a [Fisher-Yates](https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array) method; it's what I did and now works much better. – asetniop Jun 14 '17 at 23:20
  • This takes quadratic time because it does a bad uniqueness check and doesn’t have an equal chance of selecting every item because it sorts with a random comparison. – Ry- Aug 07 '17 at 22:43
-2

items.sort(() => (Math.random() > 0.5 ? 1 : -1)).slice(0, count);