Blog Con X

Algorithms3 min read

Fisher-Yates Shuffle Algorithm Explained

Eduardo Pacheco
September 25, 2026

The Fisher-Yates Shuffle, also known as the Knuth Shuffle, is an algorithm used to randomly shuffle the elements of an array.

It is considered the standard way to generate a random permutation because it ensures that every possible arrangement has an equal probability of occurring.

The algorithm is efficient, simple, and runs in linear time.

Why Not Just Use sort()?

A common mistake is trying to shuffle an array like this:

array.sort(() => Math.random() - 0.5);

While this may appear to work, it does not produce a truly uniform distribution. Some permutations become more likely than others depending on the sorting implementation.

For a fair shuffle, Fisher-Yates is the preferred solution.

How the Algorithm Works

The idea is surprisingly simple:

  1. Start from the last element in the array.
  2. Pick a random index between 0 and the current position.
  3. Swap the current element with the randomly chosen element.
  4. Move one position to the left.
  5. Repeat until the entire array has been processed.

Each element gets exactly one chance to be placed into its final position.

Step-by-Step Example

Let’s shuffle:

[1, 2, 3, 4, 5]

Step 1

Current index: 4

Random index: 1

Swap:

[1, 5, 3, 4, 2]

Step 2

Current index: 3

Random index: 2

Swap:

[1, 5, 4, 3, 2]

Step 3

Current index: 2

Random index: 0

Swap:

[4, 5, 1, 3, 2]

Step 4

Current index: 1

Random index: 1

No change:

[4, 5, 1, 3, 2]

Final shuffled array:

[4, 5, 1, 3, 2]

JavaScript Implementation

function fisherYatesShuffle(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const randomIndex = Math.floor(Math.random() * (i + 1));

    [array[i], array[randomIndex]] = [
      array[randomIndex],
      array[i]
    ];
  }

  return array;
}

const numbers = [1, 2, 3, 4, 5];

console.log(fisherYatesShuffle(numbers));

Possible Output

[3, 1, 5, 2, 4]

Because the algorithm is random, your output will likely be different each time.

Immutable Version

If you want to preserve the original array, create a copy before shuffling.

function shuffled(array) {
  const copy = [...array];

  for (let i = copy.length - 1; i > 0; i--) {
    const randomIndex = Math.floor(Math.random() * (i + 1));

    [copy[i], copy[randomIndex]] = [
      copy[randomIndex],
      copy[i]
    ];
  }

  return copy;
}

const original = [1, 2, 3, 4, 5];
const shuffledArray = shuffled(original);

console.log(original);
// [1, 2, 3, 4, 5]

console.log(shuffledArray);
// Random order

Why It Works

At each step:

  • One position is finalized.
  • Every remaining element has an equal chance of being selected.
  • No element is favored over another.

This guarantees that all possible permutations are equally likely.

For an array of length n, there are n! possible permutations.

Fisher-Yates gives each of them exactly the same probability.

Time and Space Complexity

Operation Complexity
Time O(n)
Space O(1)

For the immutable version:

Operation Complexity
Time O(n)
Space O(n)

Common Use Cases

  • Shuffling a deck of cards
  • Randomizing quiz questions
  • Randomizing game elements
  • Lottery or raffle systems
  • Sampling data for testing

Common Pitfalls

Using sort(() => Math.random() - 0.5)

array.sort(() => Math.random() - 0.5);

This approach:

  • Produces biased results
  • Depends on the JavaScript engine
  • Is generally slower than Fisher-Yates

Whenever you need a truly random shuffle, prefer Fisher-Yates.