Skip to main content

JavaScript: Shuffling Array Elements

Shuffle is different than random in term. But indeed randomness is applied in shuffling.

As in shuffling cards and giving out one random card, those are different.

Algorithmically, we can loop through the reference array, generate random index based on the reference array length, then put that item (with that random index) to a new array.

But since random can generate similar number (being floored or rounded down) as the previous one, that can lead to duplicates.

Clown bloke

For Example

We Have Input Array:

⚠️ If we simply loop through the array while creating a random index then blindly 🙈 copy the randomly chosen item to a new array, surely there will be duplicates.

❌ Unwanted Output:


🚮 Deletion Technique

We need to trim (remove the element from) the array reference after one element gets picked by the random index.

Example array input:

Then we want to shuffle the array input.

  • Create a clone of the original array (clonedArray), so that nothing will happen to the original one.

    [✒️ Side note] This is a particular post for copying object in JavaScript.

    Then create an empty array (newArray) to store the shuffled elements.

  • Loop through the clonedArray to randomly pick an element from it, then place that chosen element to newArray. Then delete/remove that particular element from the clonedArray.

    For instance this is the initial clonedArray:

    First loop, it generates random index of 1.

    That means the element "b" (index 1) is picked from the clonedArray.

    Then we put that picked element to the newArray then delete that element from clonedArray.

    And after that, the loop continues, we get another random index as 1, no problem, because the clonedArray is different now.

    So, the next picked element (with index 1) from ["a", "c", "d"] is "c".

    Now we have:

    And so on.

    As you can see in that looping sequence, the clonedArray length will decrease until it's empty, and the newArray length will increase and it will finally have the shuffled items.


🧑‍💻 Code

This is my original code back in 2015 (first published) with minor adjustment of camel casing the variable names and default function parameter (arr = []).

The original array, with the variable arr, will be left intact.

That shuffle function above can be cascaded, like so:

To shuffle the original array four times.


Using do-while, while, and forEach

Each of those will behave similarly as the first code snippet.


🏆 Fisher-Yates BOSS 😎 Technique

This technique is the most efficient, introduced by Richard Durstenfeld in 1964. This is the description at Wikipedia.

Let's take the snippet from Wikipedia:

The technique is straightforward, without introducing mutation to the clonedArray or any other computation. Get random index, then swap, BAM!

But as you can see above, the snippet doesn't return anything. It's just snippet of the technique.

This is the proper vibe.

That is actually EFFICIENT! 😲 🥳

It generates similar to the prior concept, but with peak efficiency.

The problem with pure randomness, the shuffled array can have similar sequence.

At some point, this input:

Can be shuffled as:

We want to ensure the generated sequence always differs from the original input.

We can add if condition within the loop, and we need while to accomplish it, as such:

I implement while so that there is no extra overhead inside the loop. I am only interested in simple boolean check within the loop.

The function shuffleItReal above will act as efficient as fisherYatesShuffle, but with addition that it will always generate different sequence than the reference array.


🏃‍➡️🏃‍♀️‍➡️🏃‍♂️‍➡️ Benchmark

Let's make a default array with 10,000 items, invoke each technique 1,000 times, and measure the completion duration of it.

My machine was Lenovo Legion — 15ACH6 while running the tests below. It will be different for different machine, but I believe it will still have the similar ranking for the benchmark results.

This is the snapshot of the results:

Benchmark result
Technique comparison

And this is the BOSS technique + same sequence avoidance.

The gates at the beginning of the function can be omitted — they're actually redundant, it's already included in the while condition. These conditions:

💡 We may change those as one proper gate to check whether the input type is an array before processing.

Last modified on

Comments

Monkey Raptor uses cookies or biscuits 🍪 for analytics, functionality, and advertisements. More info in Privacy Policy