The most repeated wrong answer in programming
If you search for how to shuffle an array, near the top of almost every page you will find this:
array.sort(() => Math.random() - 0.5)It is one line, it returns every element exactly once, and the result looks thoroughly shuffled. It is also measurably biased, and it has been quietly wrong in production code for twenty years because nothing about it looks broken.
This page runs it ten thousand times on your own list, next to a correct shuffle, and counts where every item landed. That is the difference between being told something is biased and seeing it.
Why it is biased
Array.sort requires a consistent comparator. Asked about the same two items, it must always give the same answer. That is not a style preference; the sorting algorithm depends on it to reason about elements it has not directly compared.
A comparator that returns a fresh random number breaks that contract completely. So the sort is not sorting anything. It is walking a decision tree taking random branches, and the shape of that tree is what produces the bias. Items tend to stay near where they started, which you can see down the diagonal of the second table on this page.
There is a second problem hiding behind the first: the result depends on which sorting algorithm the engine uses. So the same line of code is wrong in different ways in different browsers, and differently again after an engine update. It is not just biased, it is unpredictably biased.
More runs do not fix it
This catches people out, and this page is a good place to play with it.
Increase the number of runs and the fair shuffle converges neatly on even: every item appears in every position about the same number of times, and the gap shrinks the more you run. That is what noise looks like.
The biased one does not move. Ten times the runs, same skew. That is what bias looks like, and it is the reason you cannot average the problem away or dismiss it as a small sample.
The right way, which is also short
Fisher-Yates. Walk the list from the last item to the first. For each position, pick a random item at or before it and swap the two. That's all of it.
It is four lines rather than one, it makes every possible order exactly equally likely, and it has been the correct answer since 1938. The tiny detail that matters is picking from at or before the current position rather than from the whole list: the version that picks from the whole list each time is a third wrong answer that also looks fine.
Why "it looks random" proves nothing
Ten items have 3,628,800 possible orders. Twenty have more than two quintillion. You could shuffle once a second for the rest of your life and never see the same order twice.
So no amount of looking at results tells you whether a shuffle is fair. Any individual output of the biased method is a perfectly plausible shuffle. The bias only appears when you count thousands of them and compare, which is exactly what this page does and what almost nobody does before shipping.
The seed, and proving a draw was fair
Leave the seed at 0 and you get a new order every time. Put a number in and the same list always produces the same order.
That is more useful than it sounds. If you are drawing something that matters, write the seed down before the draw and tell people what it is. Afterwards anybody can enter the same list and the same seed and get the same result, which turns "trust me" into something checkable.
One limit worth stating plainly. This is fine for a raffle at work or picking the running order at a quiz. It is not suitable where somebody has a real incentive to predict or manipulate the outcome, because a seeded generator like this is predictable by design. That needs cryptographically secure randomness, which is a different job.
Common questions
Is sorting with a random comparator a real shuffle?
No. `array.sort(() => Math.random() - 0.5)` returns every element exactly once and looks completely fine, but it is measurably biased: elements tend to stay near where they started, and that is the most repeated wrong answer in programming. This page runs it ten thousand times on your own list next to a proper shuffle so you can see the difference rather than take anybody's word for it.
Why is it biased?
Because Array.sort requires a consistent comparator: asked about the same two items it must always answer the same way. A comparator returning a fresh random number breaks that contract, so the sort is not sorting, it is walking a decision tree with random branches, and the shape of that tree is the bias. It also depends on which sort algorithm the browser uses, so the same code is wrong differently in different places.
Does running it more times fix it?
No, and that surprises people every time. More runs make a fair shuffle converge on even. The biased one stays put, because it is bias rather than noise. You can watch that happen by changing the number of runs on this page.
What is the right way?
Fisher-Yates. Walk the list from the end, and swap each item with a randomly chosen one at or before it. Four lines, and every possible order comes out exactly equally likely. That is what this tool uses.
What is the seed for?
Reproducing the same order. Set a seed, write it down before the draw, and afterwards anybody can put the same list and the same seed in and get the same result. That is how you show a draw was not rigged. Leave it at 0 for a fresh order every time.
Can I use this for a prize draw or anything that matters?
For a raffle at work, yes, especially with a seed written down beforehand. For anything where somebody has a real incentive to predict or manipulate the result, no. That needs cryptographically secure randomness, which is a different job with different guarantees, and this is not it.