Get a random element from an array in JavaScript

23rd of May, 2019

TLDR: Math.floor(Math.random() * length) will give you a random index in the array, provided that length comes from array.length. The precision of this implementation over 10 million iterations is near perfect, with the biggest difference being 0.08-0.20%.

JavaScript is notorious for its tiny standard library (Standard library refers to features provided by default in the language). The lack of these functions means that you have to implement a lot of functionality yourself. This is a blessing and a curse, as you are forced to understand what is going on, but at the same time, its more time consuming, and you might end up implementing ‘bad’ (inefficient) solutions.

Some languages, like Elixir or Python, come with functionality to pick a random element from enumerable data-types (such as Arrays). In other languages, like Go or Java, you have to write the logic yourself, (sometimes) using fairly convoluted logic (Seeding random generators, etc.).

In this tiny article, I’ll quickly go through some ways to get random elements from an array in JavaScript.

Implementing the function

First, let’s frame the problem. We have an array, lets say it looks like this: const characters = [‘Peralta’, ’Santiago’, ’Linetti’, ’Boyle’,’Holt’]; // B99 Characters

Now, we want to randomly retrieve one of those names, so how do we do that? There are 5 elements, and since indexes in JS start at 0, we know that we need to randomly find a number n, where n is an integer, and 0 ≤ n ≤ 4.

The random part comes from the JS Math module, which exposes a function random - this function is invoked like this: Math.random(). The result of this call is a number n, where 0 ≤ n ≤ 0.99. (Note: Notice that it never returns 1, this is important, as we will see later).

Using the Math module, we can get a random number fitting the constraints like this: Math.floor(Math.random() * 5);. Note the ‘5’ here, since Math.random can not be 1, we do not risk ever getting 5, which would be out of bounds (or, technically, undefined in JS).

Say the value of Math.random() is 0.79, the inner part would resolve to 3.95; notice that the result is not an integer. This is why we wrap the result in Math.floor(), which takes a number, and returns the largest integer less than or equal to the number argument.

Having generated the random index, we can use it like this (notice that 5 is replaced by the length of the array provided, to make the function reusable):

const characters = [‘Peralta’, ’Santiago’, ’Linetti’, ’Boyle’,’Holt’]; // B99 Characters

function select_random_from(array) {
    const length = array.length;
    const randomIndex = Math.floor(Math.random() * length);

    return array[randomIndex];
}

console.log(select_random_from(characters)
// ‘Peralta’

console.log(select_random_from(characters)
// ‘Holt’

Note: The function name select_random_from is written in a clear and declarative way, so that it is easily understandable what is happening when reading through code using it.

On a small side note; if you want to use this function with a keyed object like this: const tasks = {ak12fb: 'Walk the dog', uk43vl: 'Go to the gym', yf54wa: 'Watch F1'} It can simply be run like so: select_random_from(Object.values(tasks)). This solution converts the values of the key-value pairs to an array, from which a random element is chosen.

Testing the function

So, that’s it 👍️ We get a random element from the array, and it seems to work. But how random is it? As discussed, the randomness comes from the Math.random function, which provides pseudo-random values. Pseudo-random means that the random value is technically predictable, if you know what it is based on (things like time of day, system stats, etc.); this is fine for our purposes, but it should not be used for anything security related (See the JS Crypto module if your random needs to be secure).

We probably don’t need crypto-level unpredictability, but we still want to check if our solution is somewhat solid, so let’s write a function to verify it. This function should run a number of times, get a random element, add the result to a tally, and finally compare the results.

function tally_randomness(iterations, randomFunction, data) {
    // Generate 'empty' array to iterate over
    const iterationsArray = [...Array(iterations).keys()];

    return iterationsArray.reduce((tallies, _current) => {
        const randomElement = randomFunction(data);
        const currentElementTally = tallies[randomElement];
        if(currentElementTally) {
            return {...tallies, [randomElement]: currentElementTally + 1};
        } else {
            return {...tallies, [randomElement]: 1};
        }
    }, {});
}

const tallies = tally_randomness(100, select_random_from, ['a', 'b']);
// tallies: {'a': 50, 'b' 50}

The result of this function is an object, which has a count of how many times each value was selected, I’ve also done a bit of stats, but removed it from this code for brevity. Here are the results of running the function with 10 million iterations (which takes just a few seconds):

Expected value: 2,000,000

Boyle: 1,999,681
Santiago: 2,003,407
Holt: 1,997,770
Linetti: 2,000,296
Peralta: 1,998,846

Maximum value: 2,003,407
Minimum value: 1,997,770
Biggest difference: 3,407 (0.17%)

Function ran 10 million iterations in: 9.2s

As you can see, the results show near perfect distribution of the values 💪🏽. The biggest difference from the mean of 2 million is 3.407 (0.17%). This means that we can probably safely use this algorithm in applications (provided its not security related).


Thank you for reading this, I hope it was helpful to you! If you have any questions/corrections, please feel free to reach out to me here.

I’ve been Niko, and you’ve been great ❤️🙏🏼 See you on the other side 🖐

See more posts