Skip to content
EN

Published: 2026-06-11

Shuffling a list without bias: the one-line mistake almost everyone makes

Shuffling a list looks like the most trivial thing in the world. You have some items; you want them in a random order; how hard can it be? Hard enough that the single most popular technique on the web — the one that shows up in the top Stack Overflow answers and in production code at companies you have heard of — produces an order that is measurably, provably unfair. Here is what goes wrong, what a correct shuffle looks like, and why "shuffle" and "draw" are not the same job.

The one-liner that looks fair and isn't

The famous bad shuffle is this: list.sort(() => Math.random() - 0.5). It reads beautifully. The comparison function returns a positive or negative number at random, so surely the sort scrambles everything evenly? It does not. A sort algorithm does not ask "which of these two comes first" for every possible pair — it asks for a carefully chosen subset of comparisons and assumes the answers are consistent. A random comparator breaks that assumption: it might say A beats B, B beats C, and C beats A all in the same run.

When you feed an inconsistent comparator to a real sort implementation, the result depends on the exact algorithm the engine uses and the order the items started in. Some items are far more likely to stay near where they began than to move to the far end. If you run the one-liner ten thousand times on a list of six and count how often each item lands in each slot, you do not get a flat distribution — you get visible diagonal banding. The first item is suspiciously likely to stay first. For a casual shuffle of your playlist nobody dies, but for anything you are calling "random and fair" out loud, it is the wrong tool.

What a correct shuffle actually does

The right answer is older than the web. It is the Fisher–Yates shuffle (the modern in-place form is sometimes credited to Durstenfeld). The idea is almost embarrassingly simple: walk the list from the last position to the first, and at each step swap the current item with a randomly chosen item from the part of the list you have not yet locked in. Each item gets exactly one fair chance to land in each position, and the whole thing runs in a single linear pass — no sorting, no comparisons, no banding.

There is one detail that even Fisher–Yates implementations get wrong, and it is the same trap that bites wheel pickers: how you pick "a random index up to i." The lazy way is Math.floor(Math.random() * (i + 1)), which inherits whatever non-uniformity Math.random() has in its low bits and adds a sprinkle of modulo-style bias on top. The honest way is to draw from the browser's cryptographic source, crypto.getRandomValues(), and use rejection sampling so every index in range is equally likely. Our Random List Shuffler does both: Fisher–Yates for the structure, crypto-backed rejection sampling for each index. The order it hands back is uniform across all possible orderings, which is the only thing "shuffle" should ever mean.

Shuffle the whole list, or just pick one?

A surprising amount of confusion comes from using a shuffle when you wanted a draw. If all you need is one winner, you do not have to order the entire list and read off the top — you just need one fair index. Shuffling first and taking the first element is not wrong, but it is more work than the job requires and it invites the temptation to "peek" at second and third place as if they meant something. They don't: only the draw you asked for is meaningful.

So match the tool to the question. Need exactly one item — a single winner, a restaurant, who goes first? Reach for the Random Single Picker . Need a full running order — turn order, an agenda, a play queue? That is a true shuffle, and the Random List Shuffler is the right call.

Drawing several without repeats

The moment you want more than one item, a new question appears: with or without replacement? "Without replacement" means once an item is drawn it cannot come up again — the right model for winners, teams, or assignments where each thing should appear at most once. "With replacement" means every draw is independent and an item can be picked twice — the right model for, say, rolling dice or sampling with the chance of repeats. People reach for "shuffle and take the first N" to get the without-replacement case, and that works, but a purpose-built picker states the intent and stops you from quietly drawing duplicates.

For drawing N distinct items from a list, the Multiple Random Picker lets you set the count and choose whether replacement is allowed. For the specific case of a giveaway with several prizes, the Random Multiple Winners tool draws a set of distinct winners in one pass — no shuffling, no manually deleting the last winner before the next draw, and the result is easy to copy straight into a spreadsheet.

When even the count should be random

Occasionally you do not want to decide how many items to draw — you want the randomness to choose that too. "Pick a random handful of these to do today." "Grab somewhere between three and five of these prompts." Doing this fairly is trickier than it looks, because the obvious approach (flip a coin for each item) skews the likely sizes toward the middle and makes it awkward to bound the result. The Random Subset Picker handles this directly: you give it a minimum and maximum size, it picks a size in that range and then draws that many distinct items — so both the count and the contents are fair.

A quick way to sanity-check any shuffler

You do not need to read the source code to catch a biased shuffle. Take a short list — four or five items is enough — and shuffle it a few dozen times, watching the first slot. If one particular item keeps showing up first far more often than the others, or if the original order keeps surviving suspiciously intact, the tool is probably sorting by a random comparator rather than doing a real shuffle. A correct shuffler shows no favourites: over many runs every item lands in every position about equally often, and that is the whole game.

The short version

Sorting by a random comparator feels clever and is quietly unfair. A real shuffle uses Fisher–Yates with a uniform random index at each step, ideally from the browser's crypto source. And before you shuffle at all, ask what you actually need: one item is a draw, the whole list is a shuffle, several distinct items is a no-replacement pick, and a random-sized handful is a subset. Pick the tool that matches the question and the fairness takes care of itself.

← Back to all posts

Send feedback

Found a bug, want a feature, or just say hi? Send it our way.