C# has several built-in methods for working with arrays and lists, but what if you need to randomize a list of items? In this article, we’ll look at some techniques we can use to randomize lists in C#. We’ll also discuss some of the pros and cons of each technique and assess how they perform.

To download the source code for this article, you can visit our GitHub repository.

Without further ado, let’s start!

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Prerequisites

First, let’s define a function to generate a list of integers. We’ll use this when testing the different ways to randomize lists. The method accepts the list’s length as a parameter and returns a List<int> object:

public List<int> OrderedInts(int size)
{
    var numbers = new List<int>();

    for (int i = 0; i < size; i++)
    {
        numbers.Add(i);
    }

    return numbers;
}

Next, we are going to initialize a List<int> object containing 1,000,000 numbers in our test class, which we intend to shuffle using the strategies we discuss: 

private readonly RandomizeGenericListsMethods _randomizeListObj;
private readonly List<int> _orderedList;

public RandomizeGenericListsUnitTests()
{
    _randomizeListObj = new RandomizeGenericListsMethods();
    _orderedList = _randomizeListObj.OrderedInts(1000000);
}

Let’s dive into some of the techniques we can use to shuffle List<T> objects in C#.

Fisher-Yates Shuffle Algorithm

This algorithm has both original and modern implementations. It’s worth familiarizing yourself with the Fisher-Yates Shuffle.

We are going to implement the modern implementation of the Fisher-Yates Shuffle algorithm:

Assuming we have an array num of n elements:
for i from n−1 iterating down to 1 do
     k ← random integer that is 0 ≤ j ≤ i
     swap num[k] with num[i]

When implementing this algorithm, we are going to start from the last element and swap it with a random element that we pick from the entire list. Then we proceed to reduce the size of the list by one and repeat the same process until we get to the first element.

First, let’s define and initialize an instance of the Random class for use in our examples:

private readonly Random _rand;

public RandomizeGenericListsMethods() 
{
    _rand = new Random();
}

Next, let’s proceed to implement our algorithm: 

public List<int> GenerateRandomLoop(List<int> listToShuffle)
{
    for (int i = listToShuffle.Count - 1; i > 0; i--)
    {
        var k = _rand.Next(i + 1);
        var value = listToShuffle[k];
        listToShuffle[k] = listToShuffle[i];
        listToShuffle[i] = value;
    }

    return listToShuffle;
}

The algorithm has an O(N) time complexity as its runtime depends on the size of the list. We also assume that the Random class takes O(1) time to generate a number

Finally, we can verify that we can successfully shuffle our List<int> object using the Fisher-Yates algorithm:

var shuffledList = _randomizeListObj.GenerateRandomLoop(_orderedList);

var firstVal = shuffledList.First();
var lastVal = shuffledList.Last();

Assert.AreNotEqual(firstVal, 0);
Assert.AreNotEqual(lastVal, 999999);

Alternatively, we can leverage existing libraries such as MoreLINQ to randomize our lists. The library has a Shuffle() method, which implements the Fisher-Yates algorithm to help us shuffle our lists. 

Randomize a List using OrderBy Random Numbers

We can use the inbuilt random class in C# to shuffle a List<T> object in C# by invoking it with the OrderBy() method in a lambda expression.

To make our example simple, let’s define a method that accepts and randomizes a List<int> object:

public List<int> GenerateRandomOrderBy(List<int> listToShuffle)
{
    var shuffledList = listToShuffle.OrderBy(_ => _rand.Next()).ToList();

    return shuffledList;
}

The method invokes the OrderBy() and rand.Next() functions to shuffle the listToShuffle object by ordering it by random numbers. 

Next, we can verify that our method successfully shuffles a list:

var shuffledList = _randomizeListObj.GenerateRandomOrderBy(_orderedList);

var firstVal = shuffledList.First();
var lastVal = shuffledList.Last();

Assert.AreNotEqual(firstVal, 0);
Assert.AreNotEqual(lastVal, 999999);

Shuffle a List using OrderBy by Guid Values 

We use a similar strategy as the previous example, except that we substitute the Random class with the Guid.NewGuid() method in our OrderBy() clause:

public List<int> GenerateRandomOrderByGuid(List<int> listToShuffle)
{
    var shuffledList = listToShuffle.OrderBy(_ => Guid.NewGuid()).ToList();

    return shuffledList;
}

Let’s verify that we can shuffle our List<int> object with this strategy:

var shuffledList = _randomizeListObj.GenerateRandomOrderByGuid(_orderedList);

var firstVal = shuffledList.First();
var lastVal = shuffledList.Last();

Assert.AreNotEqual(firstVal, 0);
Assert.AreNotEqual(lastVal, 999999);     

Performance Benchmarks

First, we are going to create a new object that generates a List<int> object to shuffle when performing these benchmarks:

public IEnumerable<List<int>> SampleList()
{
    yield return OrderedInts(1000000);
}

We use the yield operator in our example to create the list on demand, which has some performance benefits. 

Next, let’s analyze our benchmark results:

|                    Method |      Mean |     Error |    StdDev | Rank |  Allocated |
|-------------------------- |----------:|----------:|----------:|-----:|-----------:|
|        GenerateRandomLoop |  24.92 ms |  1.645 ms |  4.798 ms |    1 |       24 B |
|     GenerateRandomOrderBy | 428.39 ms | 21.995 ms | 64.506 ms |    2 | 16000752 B |
| GenerateRandomOrderByGuid | 699.60 ms | 28.362 ms | 79.994 ms |    3 | 28000688 B |

We can see that the Fisher-Yates algorithm is almost twenty times faster than the other Linq-based functions. The OrderBy() method implements the quicksort algorithm, which has a worst-case complexity of O(N2while our Fisher-Yates algorithm implementation takes O(N).

Our Guid solution seems to be almost one and a half times slower than our Random solution because Guid values consume more memory, which affects how the algorithm performs.

What Are Some Benefits of Randomizing Lists?

First, creating random lists in C# helps us to easily create dynamic and flexible content for our applications.

Additionally, randomizing lists allows us to create more engaging user experiences by keeping things interesting and unpredictable.

Furthermore, this approach offers a number of performance benefits, since it doesn’t require us to store and manipulate large amounts of data.

Drawbacks of Creating Random Lists

One of the drawbacks of randomly generating lists is that there’s a tendency for the same elements to be repeated more often than would be ideal. This could potentially lead to suboptimal results when using these lists in applications, as certain elements will appear more frequently than others.

Conclusion 

In this article, we learn how to randomize a list in C#. We can see that there are a few different ways to do this, and each has its benefits and drawbacks. We are looking forward to getting your feedback and learning together!

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!