Coder Perfect

How do I acquire a random number of elements from an array?

Problem

I’m working on a solution to the problem of ‘how to access elements randomly from an array in javascript.’ I discovered a plethora of resources on the subject. Get a random item from a JavaScript array, for example.

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

However, we can only select one item from the array in this case. How can we get more than one element if we desire them all? How can we extract many elements from an array?

Asked by Shyam Dixit

Solution #1

There are only 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);

Answered by Abdennour TOUMI

Solution #2

Take a look at this non-destructive (and quick) 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;
}

Answered by Bergi

Solution #3

There is a one-liner solution to this problem.

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

Answered by Olalekan Sogunle

Solution #4

_.sample and _.sampleSize are lodash functions.

Gets one or n random elements from a collection with unique keys up to the collection’s size.

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

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

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

Answered by nodejh

Solution #5

Using the Python standard library’s.sample:

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;
}

Lib/random.py implementation transferred.

Notes:

In comparison to the acceptable answer:

Answered by Derek 朕會功夫

Post is based on https://stackoverflow.com/questions/19269545/how-to-get-a-number-of-random-elements-from-an-array