How to randomize (shuffle) a JavaScript array?

To shuffle a JavaScript array fairly and efficiently, use the Fisher-Yates (Knuth) shuffle algorithm. This method ensures every permutation is equally likely, unlike simpler approaches (e.g., sort() with Math.random()), which introduce bias.

Correct Implementation

function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; i--) {
    // Pick a random index from 0 to i (inclusive)
    const j = Math.floor(Math.random() * (i + 1));
    // Swap elements at positions i and j
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

// Usage:
const myArray = [1, 2, 3, 4, 5];
shuffleArray(myArray);
console.log(myArray); // e.g., [3, 1, 5, 2, 4]

Why Avoid array.sort(() => Math.random() - 0.5)?

This method is biased because:

  1. The sorting algorithm compares elements multiple times with inconsistent randomness.
  2. Some elements have higher probabilities of ending up in specific positions.

Key Features of Fisher-Yates

  • In-place shuffling: Modifies the original array (use [...array] to create a copy first if needed).
  • Linear time complexity: O(n) efficiency.
  • Uniform distribution: All permutations are equally likely.

Shuffle Without Mutating the Original Array

Create a copy to preserve the original:

function shuffleCopy(array) {
  const copy = [...array];
  for (let i = copy.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [copy[i], copy[j]] = [copy[j], copy[i]];
  }
  return copy;
}

// Usage:
const original = [1, 2, 3];
const shuffled = shuffleCopy(original);
console.log(original); // [1, 2, 3] (unchanged)
console.log(shuffled); // e.g., [3, 1, 2]

Comparison Table

MethodFair ShuffleTime ComplexityModifies Original Array
Fisher-Yates✅ YesO(n)✅ Yes (optional)
sort() + random()❌ NoO(n log n)✅ Yes

Visual Example of Fisher-Yates

Initial Array: [A, B, C, D]
Steps:

  1. Swap D (index 3) with a random element (e.g., B at index 1) → [A, D, C, B]
  2. Swap C (index 2) with a random element (e.g., A at index 0) → [C, D, A, B]
  3. Swap D (index 1) with itself → no change.

Result: [C, D, A, B]

Browser/Environment Support

Works in all modern browsers (ES6+). For legacy environments, replace the destructuring assignment with a temporary variable:

// Swap without destructuring:
const temp = array[i];
array[i] = array[j];
array[j] = temp;

Summary

Use the Fisher-Yates algorithm for unbiased shuffling. Avoid Math.random()-based sorting for critical applications.

Leave a Reply

Your email address will not be published. Required fields are marked *