Text Randomizer

Shuffles lines, words, characters or paragraphs with Fisher-Yates, because sort with a random comparator is measurably skewed and browser-dependent.

Enable JavaScript to customise; default output below.

Shuffle

Characters means grapheme clusters, so an emoji or an accented letter moves as one piece.

Live preview shuffled.txt
Alice Nakamura
Ben Osei
Carla Duarte
Daniyal Khan
Eva Lindqvist
Farid Rahman
Grace Mbeki
Hanna Virtanen

Not shuffled yet  the order is chosen in your browser, so this is the input
Lines             8

Method
  algorithm       Fisher-Yates, which gives every order equal probability
  not             sort( () => Math.random() - 0.5 ), which is measurably skewed
  source          crypto.getRandomValues, by rejection sampling

`array.sort( () => Math.random() - 0.5 )` is the shuffle everyone knows
and it does not work. A comparator has to be consistent: asking it the
same question twice must give the same answer, and a sort is entitled to
rely on that. A random comparator breaks it, so the output depends on
the sort algorithm and is skewed in a way that differs between browsers.

Fisher-Yates walks from the end, swapping each item with a uniformly
chosen one at or below its position. That gives all n! orders equal
probability. Choosing the swap index from the whole array each time
instead is the classic naive version, and it favours some orders over
others.

About one item in n stays in its original place in a fair shuffle, so a
shuffle where nothing moved is not necessarily broken and a shuffle
where everything moved is not necessarily better. The count above is
there so you can see the number rather than judge by eye.

Characters means grapheme clusters here, not code units, so shuffling
text with emoji or combining accents in it moves whole characters.
Shuffling by UTF-16 unit takes an emoji apart into surrogate halves and
produces replacement squares.

Shuffling is not anonymising. The same words in a different order carry
most of the same information, and a shuffled list of customer names is
still a list of customer names.

For a giveaway or anything with a prize, the randomness matters more
than the algorithm. This uses `crypto.getRandomValues`, so the sequence
is not predictable from previous output the way `Math.random` is.

The result cannot be reproduced, on purpose. There is no seed, because a
reproducible shuffle is a different tool with different uses, and a draw
that can be replayed is a draw that can be gamed.

Output is valid and updates as you type.

array.sort( () => Math.random() - 0.5 ) is the best-known way to shuffle a list in JavaScript, and it is not a shuffle.

A comparator has to be consistent: asked the same question twice it must give the same answer, and a sort is entitled to rely on that. A random comparator breaks the contract, so what comes out depends on the sorting algorithm. In V8 the first elements stay near the front far more often than chance; another engine is skewed differently. The result looks shuffled and is not.

Fisher-Yates is three lines and correct: walk from the end, swapping each item with a uniformly chosen one at or below its position. That gives every possible order the same probability, and it is what this uses.

How to use

  1. Paste the list.
  2. Choose what to shuffle: lines, words, characters or paragraphs.
  3. Tick the box to hold a header row in place.

Example

Eight names, shuffled by line:

Grace Mbeki
Alice Nakamura
Daniyal Khan
Eva Lindqvist
Ben Osei
Farid Rahman
Hanna Virtanen
Carla Duarte

Lines                 8
In a different place  7 of 8
  expected            about 7, since one item in n stays put by chance

Method
  algorithm           Fisher-Yates, which gives every order equal probability
  not                 sort( () => Math.random() - 0.5 ), which is measurably skewed
  source              crypto.getRandomValues, by rejection sampling

Seven of eight moved, and one staying put is expected rather than a sign of a problem.

Pitfalls

The one-line sort shuffle is broken and looks fine. That is what makes it durable: the output is plausible, so nobody checks. It only shows up when somebody measures the distribution over thousands of runs, which is what the test suite here does.

The naive Fisher-Yates variant is also biased. Choosing the swap index from the whole array each time instead of from the unshuffled part produces n^n equally likely paths over n! orders, which cannot divide evenly, so some orders come up more often. The direction of the walk matters.

One item in n stays put in a fair shuffle. A shuffle where nothing moved is not necessarily broken, and one where everything moved is not necessarily better. The count is printed so you can look at the number rather than judge by eye.

Characters means grapheme clusters here. Shuffling by UTF-16 code unit takes an emoji apart into surrogate halves and produces replacement squares, and moves a combining accent onto the wrong letter. Whole characters move as one piece.

Shuffling is not anonymising. The same words in a different order carry most of the same information, and a shuffled list of customer names is still a list of customer names.

A shuffle by word destroys sentence structure and keeps the vocabulary. For scrambling text that still has to be read as a sentence, this is the wrong tool. For an ordering draw it is the right one.

There is no seed, on purpose. A reproducible shuffle is a different tool with different uses, and a draw that can be replayed is a draw that can be gamed.

Compatibility

Everything runs in the browser: nothing is uploaded and nothing is stored, which is the point for a list of names.

The randomness is crypto.getRandomValues, and the swap index is drawn by rejection sampling so that every position is equally likely. Using a modulo there would bias the shuffle in a subtler way than the sort trick does.

Characters are split with Intl.Segmenter grapheme granularity, with a fallback that keeps combining marks and zero-width-joiner sequences together where the segmenter is missing.

The distribution is checked in the test suite over 40,000 shuffles of a four-item list, asserting that each item lands in each position within a percentage point and a half of a quarter. The sort-comparator version fails that test comfortably, which is why the assertion is there.

Frequently asked questions

What is the correct way to shuffle an array in JavaScript?
Fisher-Yates: walk i from the last index down to 1, draw j as a uniform integer in 0..i, and swap a[ i ] with a[ j ]. Three lines. Walking downwards and choosing j from 0..i rather than from the whole array is what makes it uniform.
Is Math.random good enough for a shuffle?
For a game, a carousel or a test fixture, yes. For a prize draw or anything where predicting the order is worth something, use crypto.getRandomValues, which is what this does.
Can I shuffle only part of the list?
Tick the box to hold the first item, which covers a header row. For anything more selective, split the list, shuffle the part you want, and put it back together with the text merger.
How do I pick one random item?
Shuffle and take the first, which is what a draw is. For a single pick from a numeric range, the random number generator on this site is the more direct tool.
Will the same input give the same output?
No, and that is deliberate. Every run draws fresh randomness, so there is no way to reproduce a previous order.
Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.