Question

How to Randomize a List<T> in C#

csharplistrandomshuffle

Question

I want to randomize the order of a generic List<T> in C#. I have a finite set of 75 numbers stored in a list, and I would like to place them into a random order so I can draw them one by one for a lottery-style application.

What is the best way to shuffle a List<T> so that each item has a fair chance of appearing in any position?

Short Answer

By the end of this page, you will understand how to shuffle a List<T> in C# using the correct approach, why some randomization techniques are biased or inefficient, and how to apply a proper shuffle in real applications such as games, lotteries, quizzes, and randomized processing.

Concept

Randomizing a list means reordering its elements so the order is unpredictable. In C#, this is commonly called shuffling a list.

The most important idea is that not all “random-looking” solutions are equally correct. A good shuffle should:

  • Move every item exactly once into a new random position
  • Give all possible orderings a fair chance
  • Run efficiently, especially for larger lists

The standard algorithm for this is the Fisher-Yates shuffle. It works by walking backward through the list and swapping each element with a randomly chosen earlier element, including itself.

Why this matters:

  • In a lottery-style app, you want each number to be equally likely to appear first, second, third, and so on.
  • In games, biased shuffling can make results unfair.
  • In testing or data processing, predictable or poor randomization can produce misleading outcomes.

A common beginner mistake is to sort by a random key, such as using OrderBy(x => random.Next()). This may look convenient, but it is not the best tool for a true shuffle and can be less efficient and potentially biased depending on collisions and implementation details.

So the core concept behind this question is not just “how do I randomize a list,” but how do I shuffle a list correctly and fairly in C#.

Mental Model

Imagine you have a deck of numbered cards.

You start at the last card position and say:

  • "Pick any card from position 0 to this position."
  • Swap it into the current spot.
  • Move one position left and repeat.

This is like filling the list from the end backward, choosing a random remaining item each time.

Why this model is useful:

  • At each step, you only choose from items not already locked into place.
  • Once a position is filled, you never disturb it again.
  • This guarantees a fair shuffle when done correctly.

So instead of “mixing everything around randomly,” think of shuffling as placing one random remaining item into each final position.

Take Quiz

Syntax and Examples

The classic way to shuffle a List<T> in C# is to use the Fisher-Yates algorithm.

using System;
using System.Collections.Generic;

public static class ListExtensions
{
    public static void Shuffle<T>(this List<T> list, Random rng)
    {
        for (int i = list.Count - 1; i > 0; i--)
        {
            int j = rng.Next(i + 1);
            (list[i], list[j]) = (list[j], list[i]);
        }
    }
}

Example usage:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var numbers = new List<int>();

        for (int i = 1; i <= 75; i++)
        {
            numbers.Add(i);
        }

        var rng = new Random();
        numbers.Shuffle(rng);

        foreach (var number in numbers)
        {
            Console.WriteLine(number);
        }
    }
}

How it works:

  • i starts at the last index.
  • rng.Next(i + 1) picks a random index from 0 through i.
  • The item at i is swapped with the item at j.
  • The process repeats until the list is shuffled.

This modifies the original list in place, which means it does not create a separate shuffled copy.

If you want a new shuffled list instead, you can copy first:

var original = new List<int> { 1, 2, 3, 4, 5 };
var shuffled = new List<int>(original);
shuffled.Shuffle(new Random());

This keeps original unchanged.

Step by Step Execution

Consider this small list:

var numbers = new List<int> { 10, 20, 30, 40 };
var rng = new Random();
numbers.Shuffle(rng);

Using the shuffle method:

public static void Shuffle<T>(this List<T> list, Random rng)
{
    for (int i = list.Count - 1; i > 0; i--)
    {
        int j = rng.Next(i + 1);
        (list[i], list[j]) = (list[j], list[i]);
    }
}

Let’s trace one possible run.

Initial list:

[10, 20, 30, 40]

Step 1

i = 3

  • Randomly pick j from 0 to 3
  • Suppose j = 1
  • Swap index 3 and index 1

List becomes:

[10, 40, 30, 20]

Step 2

i = 2

  • Randomly pick j from 0 to 2
  • Suppose j = 0
  • Swap index 2 and index 0

List becomes:

[30, 40, 10, 20]

Step 3

i = 1

  • Randomly pick j from 0 to 1
  • Suppose j = 1
  • Swap index 1 with itself

List stays:

[30, 40, 10, 20]

Loop ends because i is no longer greater than 0.

Final shuffled list:

[30, 40, 10, 20]

Important detail: swapping with the same index is allowed. That is part of what keeps the shuffle fair.

Real World Use Cases

Shuffling a list is useful in many real applications:

  • Lottery or bingo apps
    • Randomize a fixed set of numbers and draw them one at a time.
  • Card games
    • Shuffle a deck before dealing cards.
  • Quiz applications
    • Randomize question order or answer choices.
  • Music playlists
    • Play songs in a random order.
  • Load balancing or task processing
    • Randomize work items to avoid fixed processing order.
  • Testing and simulations
    • Randomize data to test behavior under different input sequences.

Example: drawing lottery numbers one by one

var numbers = Enumerable.Range(1, 75).ToList();
numbers.Shuffle(new Random());

foreach (var draw in numbers)
{
    Console.WriteLine($"Drawn: {draw}");
}

This approach is simple because the list is shuffled once, then consumed in order.

Take Quiz

Real Codebase Usage

In real codebases, developers usually wrap shuffling logic in a reusable method or extension method so it can be applied anywhere.

Common patterns include:

Reusable extension method

This is the most common style for List<T>:

public static class ListExtensions
{
    public static void Shuffle<T>(this List<T> list, Random rng)
    {
        for (int i = list.Count - 1; i > 0; i--)
        {
            int j = rng.Next(i + 1);
            (list[i], list[j]) = (list[j], list[i]);
        }
    }
}

Validation and guard clauses

In production code, you often validate inputs early:

public static void Shuffle<T>(this List<T> list, Random rng)
{
    if (list == null)
        throw new ArgumentNullException(nameof(list));

    if (rng == null)
        throw new ArgumentNullException(nameof(rng));

    for (int i = list.Count - 1; i > 0; i--)
    {
        int j = rng.Next(i + 1);
        (list[i], list[j]) = (list[j], list[i]);
    }
}

Reusing a single Random

A common practice is to create one Random instance and reuse it, instead of creating a new one repeatedly.

private static readonly Random _rng = new Random();

This avoids poor randomness caused by repeatedly constructing Random too quickly.

Shuffle then process

Many applications shuffle once and then process in order:

  • randomize users for A/B assignment
  • randomize jobs before batch processing
  • randomize quiz questions before display

Copy before shuffling

If the original sequence must be preserved, developers usually clone it first:

var shuffledUsers = users.ToList();
shuffledUsers.Shuffle(_rng);

This is common in services, APIs, and business logic where the original data should remain unchanged.

Common Mistakes

Here are the most common mistakes beginners make when randomizing a list in C#.

1. Creating Random repeatedly

Broken approach:

for (int i = 0; i < 10; i++)
{
    var rng = new Random();
    Console.WriteLine(rng.Next());
}

Problem:

  • If Random is created many times in quick succession, it may use similar seeds.
  • That can produce repeated or low-quality results.

Better:

var rng = new Random();
for (int i = 0; i < 10; i++)
{
    Console.WriteLine(rng.Next());
}

2. Using OrderBy(x => rng.Next()) as a shuffle

Example:

var shuffled = numbers.OrderBy(x => rng.Next()).ToList();

Why this is not ideal:

  • It is less direct than Fisher-Yates.
  • It depends on sorting instead of true in-place shuffling.
  • Random key collisions can affect fairness.
  • It is usually less efficient.

Use Fisher-Yates for proper shuffling.

3. Using the wrong range for Next

Broken code:

int j = rng.Next(i); // wrong for Fisher-Yates in this form

Problem:

  • rng.Next(i) returns values from 0 to i - 1.
  • That excludes i, which changes the algorithm and can bias the result.

Correct:

int j = rng.Next(i + 1);

4. Forgetting that the list is modified in place

Example:

numbers.Shuffle(rng);

After this call, numbers itself is changed.

If you need the original too, copy it first:

var shuffled = new List<int>(numbers);
shuffled.Shuffle(rng);

5. Writing a swap incorrectly

Broken code:

list[i] = list[j];
list[j] = list[i];

Problem:

  • The second assignment uses an already overwritten value.

Correct options:

T temp = list[i];
list[i] = list[j];
list[j] = temp;

Or tuple swap:

(list[i], list[j]) = (list[j], list[i]);

Comparisons

Here is how common approaches compare.

ApproachFair shufflePerformanceChanges original listNotes
Fisher-Yates shuffleYesExcellent, O(n)YesBest standard choice for List<T>
Copy + Fisher-YatesYesGood, O(n) plus copyNoBest when original must stay unchanged
OrderBy(x => rng.Next())Not idealSlower, O(n log n)NoConvenient but not the preferred shuffle
Manual random picking with removalCan be fairOften slowerUsually creates new listSimpler to understand, less efficient for large lists

Fisher-Yates vs sorting by random key

var shuffled = numbers.OrderBy(x => rng.Next()).ToList();

This works for some casual use cases, but Fisher-Yates is generally better because:

  • it is designed specifically for shuffling
  • it is more efficient
  • it avoids relying on sorting behavior

In-place shuffle vs new shuffled list

OptionWhen to use
In-place shuffleWhen you no longer need the original order
New shuffled copyWhen the original list must remain unchanged

List<T> vs IEnumerable<T>

  • List<T> is easy to shuffle in place because it supports indexing.
  • IEnumerable<T> may need to be converted to a list first:
var list = source.ToList();
list.Shuffle(rng);
Take Quiz

Cheat Sheet

public static void Shuffle<T>(this List<T> list, Random rng)
{
    for (int i = list.Count - 1; i > 0; i--)
    {
        int j = rng.Next(i + 1);
        (list[i], list[j]) = (list[j], list[i]);
    }
}

Rules

  • Use Fisher-Yates to shuffle a List<T> fairly.
  • Loop from list.Count - 1 down to 1.
  • Pick j with rng.Next(i + 1).
  • Swap list[i] and list[j].
  • Reuse a single Random instance when possible.

Preserve the original list

var copy = new List<int>(original);
copy.Shuffle(rng);

Create a list of 1 through 75

var numbers = Enumerable.Range(1, 75).ToList();

Common bad idea

numbers.OrderBy(x => rng.Next()).ToList();
  • convenient
  • not the preferred shuffle
  • slower than Fisher-Yates

Edge cases

  • Empty list: nothing happens
  • One-item list: nothing happens
  • null list: should throw ArgumentNullException if validated
  • null random generator: should throw ArgumentNullException if validated

FAQ

How do I shuffle a List<T> in C#?

Use the Fisher-Yates algorithm. It swaps each item with a randomly chosen earlier item, producing an efficient and fair shuffle.

Is OrderBy(x => random.Next()) a good way to randomize a list?

It may appear to work, but it is not the preferred method for a proper shuffle. Fisher-Yates is more efficient and more reliable for fair randomization.

Does shuffling a list change the original list?

Yes, if you shuffle in place. If you want to keep the original order, create a copy first and shuffle the copy.

Why should I reuse the same Random object?

Creating many Random instances quickly can lead to repeated or poor-quality random values. Reusing one instance avoids that problem.

Can I shuffle a list of any type, not just numbers?

Yes. A generic method like Shuffle<T> works with strings, objects, custom classes, and numbers.

What algorithm is typically used to shuffle a list?

The standard answer is the Fisher-Yates shuffle, sometimes called the Knuth shuffle.

How can I draw lottery numbers one at a time after shuffling?

Shuffle the list once, then read items from the beginning to the end. Each next item is the next draw.

Do I need LINQ to shuffle a list?

No. A loop with swaps is enough, and it is usually the better approach for this task.

Take Quiz

Mini Project

Description

Build a simple lottery number drawer in C#. The program should create numbers from 1 to 75, shuffle them, and then display the numbers in the order they are drawn. This demonstrates how shuffling is used in a realistic application where each number should appear exactly once in a random order.

Goal

Create a console app that generates 75 numbers, shuffles them fairly, and prints them as lottery draws.

Requirements

  • Create a list containing the numbers 1 through 75.
  • Shuffle the list using a reusable Shuffle<T> method.
  • Print each number in its randomized order.
  • Ensure each number appears exactly once.
  • Reuse a single Random instance.
Take Quiz

Keep learning

Related questions

View more