pseudo-random shuffle
one-pass algorithm
programming
randomization techniques
algorithm efficiency

What's a good one-pass pseudo-random shuffle?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A good one-pass pseudo-random shuffle for arrays is Fisher-Yates (Knuth shuffle). It runs in linear time, uses constant extra memory, and gives each permutation equal probability when the random number generator is unbiased.

Many "shuffle" snippets found online are biased because they choose swap indices from the full range at each step. This article shows the correct algorithm and explains how to validate fairness.

Core Sections

1. Correct Fisher-Yates algorithm

python
1import random
2
3def shuffle_in_place(arr):
4    for i in range(len(arr) - 1, 0, -1):
5        j = random.randint(0, i)
6        arr[i], arr[j] = arr[j], arr[i]

At position i, only indices [0..i] are eligible, which preserves uniformity.

2. Why naive approaches are biased

python
1# biased approach, do not use
2for i in range(len(arr)):
3    j = random.randint(0, len(arr)-1)
4    arr[i], arr[j] = arr[j], arr[i]

This method overweights some permutations and underweights others.

3. Use deterministic seeds in tests

python
1rng = random.Random(123)
2arr = [1,2,3,4,5]
3for i in range(len(arr)-1, 0, -1):
4    j = rng.randint(0, i)
5    arr[i], arr[j] = arr[j], arr[i]
6print(arr)

Seeding enables reproducible unit tests while production code should use non-fixed seeds.

4. Streaming and very large datasets

If full in-memory shuffle is impossible, use reservoir sampling for subset selection or external-memory shuffle strategies. Fisher-Yates requires random access to all elements.

5. Build a repeatable validation checklist

After implementing one-pass shuffle implementations, create a small validation pack that runs the same way on developer machines, CI, and staging. The checklist should include a baseline case, an edge case, and a failure-path case with expected outcomes written in plain language. This avoids the common situation where a workflow appears correct in one environment but fails under a slightly different runtime, dependency version, or input distribution.

A useful checklist should also capture environment assumptions explicitly: runtime version, dependency versions, configuration flags, and external services required by the scenario. Teams often skip this because it feels obvious during initial implementation, but those hidden assumptions are exactly what cause regressions during upgrades and handoffs.

text
1validation checklist
2- baseline scenario with expected output shape and values
3- edge scenario with constrained or unusual input
4- failure scenario with expected fallback or error behavior
5- runtime/dependency/config assumptions for reproducibility

Treat this checklist as a versioned artifact. If code behavior changes, update expected results in the same pull request rather than relying on informal tribal memory. Coupling implementation and validation updates keeps one-pass shuffle implementations reliable as the codebase evolves.

6. Operational hardening and maintenance

Long-term reliability for one-pass shuffle implementations depends on observability and clear ownership. Add structured logs and metrics around the most failure-prone operations so incident responders can quickly identify whether failures come from input quality, configuration mismatch, external dependency drift, or code regressions. Without those signals, teams spend most of incident time reconstructing context instead of fixing root causes.

Also define who owns periodic compatibility checks. Libraries, runtimes, cloud APIs, and tooling change over time, and silent drift is common. Schedule lightweight smoke checks that run even when no feature work is active, and record results so there is an audit trail for when behavior started to diverge.

bash
# example maintenance check command pattern
make smoke-test

Finally, document rollback criteria ahead of time. If a deployment changes one-pass shuffle implementations behavior unexpectedly, the team should know when to roll back immediately versus when to hot-fix forward. This turns operational response from improvisation into a controlled process and prevents repeated incidents.

Common Pitfalls

  • Picking random swap index from full array for every step.
  • Using weak RNG where security or fairness requirements are strict.
  • Re-seeding RNG repeatedly inside loops.
  • Assuming in-place shuffle works for data streams without random access.
  • Forgetting to test distribution quality for critical use cases.

Summary

Fisher-Yates is the standard one-pass pseudo-random shuffle for finite arrays: simple, fast, and unbiased when implemented correctly. Keep index selection range bounded to current position, use suitable RNG quality, and validate behavior with reproducible tests or distribution checks when fairness matters.


Course illustration
Course illustration

All Rights Reserved.