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 previous one, that can lead to duplicates.
For example
We have an array:
Then loop through it while blindly creating a random index to copy the randomly chosen item to a new array, surely there will be duplicates.
Unwanted output:
Deletion
We need to trim 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.Then create an empty array (
bufferArray
) to store the shuffled elements. -
Loop through the
clonedArray
to randomly pick an element from it, then place that chosen element tobufferArray
. Then delete/remove that particular element from theclonedArray
.For instance this is the initial
clonedArray
:First loop, it generates random index of
1
.That means the element
"b"
(index1
) is picked from theclonedArray
.Then we put that picked element to the
bufferArray
then delete that element fromclonedArray
.And after that, the loop continues, we get another random index as
1
, no problem, because theclonedArray
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 thebufferArray
length will increase and it will 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.
This is the snapshot of the results:
And this is the BOSS technique + same sequence avoidance.
Comments
Post a Comment