In this article, we will look at how we can efficiently randomize an array in C#. We’ll explore several ways of achieving that and then we’ll compare the performance of each approach.

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

Let’s start randomizing!

Initial Setup

Before we can start randomizing our arrays, we need a way to initialize them:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
public static class ArrayFunctions
{
    public static int[] GetOrderedArray(int numberOfElements)
    {
        var array = new int[numberOfElements];

        for (int i = 0; i < numberOfElements; i++)
        {
            array[i] = i;
        }          return array;
    }
}

We define the ArrayFunctions class with one method. The GetOrderedArray() method is static and generates an array of integers in ascending order, based on the specified length provided as the parameter. The generated array is returned as the result.

Randomize an Array in C# Using LINQ

LINQ is one of the most powerful tools we have at our disposal in C#. It provides us with various ways of manipulating data.

We often use it to query or filter datasets, but we can utilize it for randomizing as well. We can achieve that in several ways, all using the OrderBy method.

Randomize an Array in C# Using GUID

Let’s create a method utilizing the Guid class:

public static int[] RandomizeWithOrderByAndGuid(int[] array) =>
    array.OrderBy(x => Guid.NewGuid()).ToArray();

We create a new static RandomizeWithOrderByAndGuid() method. It directly returns the input array ordered by Guid.NewGuid(). As OrderBy() returns an IOrderedEnumerable, we use ToArray method to convert the result back to an array.

The OrderBy() method is used to sort data based on a specified key. By ordering based on Guid.NewGuid(),  which generates a unique ID for each element in the array, we effectively shuffle the array elements randomly.

Randomize an Array in C# Using the Random Class

Next, we will rely on the Random class:

public static int[] RandomizeWithOrderByAndRandom(int[] array) =>
    array.OrderBy(x => Random.Shared.Next()).ToArray();

In our ArrayFunctions class, we create the RandomizeWithOrderByAndRandom() method. Again, we use the OrderBy() method from LINQ to shuffle the elements of the array. This time we sort them based on randomly generated numbers using the Next method of Random.Shared. Finally, we convert the result to an array and return it.

Randomize an Array in C# Using the Fisher-Yates Algorithm

We can use the Fisher-Yates algorithm to randomly re-order the elements of an array:

public static int[] RandomizeWithFisherYates(int[] array)
{
    int count = array.Length;

    while (count > 1)
    {
        int i = Random.Shared.Next(count--);
        (array[i], array[count]) = (array[count], array[i]);
    }

    return array;
}

We create the RandomizeWithFisherYates() method that takes an integer array as input. Inside the method, we initialize the count variable with the length of the input array. In each iteration of a while loop, a random index is generated, and the element at that index is swapped with the element pointed by the count variable using a Tuple. This process continues until count becomes 1. Finally, we return the modified array.

This, however, won’t be a fair race. This approach works directly on, and returns, the input array where the OrderBy methods return a copy of the array.

Let’s even the playing field and create a second version of the Fisher-Yates algorithm:

public static int[] RandomizeWithFisherYatesCopiedArray(int[] array)
{
    int count = array.Length;
    var arrayCopy = new int[count];

    Array.Copy(array, arrayCopy, count);

    while (count > 1)
    {
        int i = Random.Shared.Next(count--);
        (arrayCopy[i], arrayCopy[count]) = (arrayCopy[count], arrayCopy[i]);
    }

    return arrayCopy;
}

It is almost identical to the original RandomizeWithFisherYates() method with the exception that we use the Array.Copy() method to copy the input array. In the rest of the method, we work with the arrayCopy variable and return it once we are done.

Testing Array Randomization Logic

Once we have your different randomization methods, we need to make sure they work as intended:

public class ArrayFunctionsTests
{
    private readonly int[] _array;
    private const int ARRAY_SIZE = 1000;

    public ArrayFunctionsTests()
    {
        _array = ArrayFunctions.GetOrderedArray(ARRAY_SIZE);
    }
}	

Using the xUnit framework, we create a test project and the ArrayFunctionsTests class. It includes fields for an array and its size. In the constructor, we initialize the _array by calling the GetOrderedArray() method of our ArrayFunctions class.

Then, we test our methods:

[Fact]
public void WhenRandomizeWithOrderByAndGuidIsInvoked_ThenArrayIsRandomized()
{
    // Act
    var randomizedArray = ArrayFunctions.RandomizeWithOrderByAndGuid(_array);

    // Assert
    randomizedArray
        .Should().NotBeNullOrEmpty()
        .And.NotBeInAscendingOrder()
        .And.NotBeInDescendingOrder();
}

Inside the test method, we use the RandomizeWithOrderByAndGuid() method of the ArrayFunctions class to randomize the ordered _array variable. We store the result in the randomizedArray variable. Then, using the FluentAssertions library, we assert that the randomizedArray variable should not be null or empty, should not be in ascending order, and should not be in descending order as well.

This way, we verify that the RandomizeWithOrderByAndGuid() method successfully produces a different order than the original array and the array is not ordered in any direction.

To test the other three methods we have created in this article, we can use the same approach and change the method we invoke in our test.

Performance Considerations When Randomizing an Array in C#

When choosing a way to randomize an array in C# we also need to think about performance. We can use BenchmarkDotNet to measure performance and memory allocation:

|                              Method |      Mean |     Error |    StdDev | Rank | Allocated |
|------------------------------------ |----------:|----------:|----------:|-----:|----------:|
|            RandomizeWithFisherYates |  1.400 ms | 0.0069 ms | 0.0065 ms |    1 |       1 B |
| RandomizeWithFisherYatesCopiedArray |  1.526 ms | 0.0025 ms | 0.0024 ms |    2 |  400057 B |
|       RandomizeWithOrderByAndRandom | 17.398 ms | 0.1137 ms | 0.1008 ms |    3 | 1602657 B |
|         RandomizeWithOrderByAndGuid | 25.921 ms | 0.0739 ms | 0.0617 ms |    4 | 2803288 B |

The benchmark we use measures the mean execution time, error, standard deviation, and memory allocation for each method.

RandomizeWithFisherYates() method is the most efficient by far, with an execution time of about 1 400 microseconds. It ranks first and has almost no memory allocation at all.

Our modified version of the Fisher-Yates algorithm for evening the comparison, RandomizeWithFisherYatesCopiedArray() ranks second, with 1 500 microseconds. It has more memory allocation than the original version due to copying the input array but overall performs extremely well.

Then, the RandomizeWithOrderByAndRandom() method has an execution time of around 17 000 microseconds and significantly higher memory allocation compared to the previous two methods – it ranks third.

Finally, RandomizeWithOrderByAndGuid() has an execution time of about 26 000 microseconds. It ranks last among the four methods and also has the highest memory allocation.

Conclusion

In this article, we explored different ways to randomize an array in C#. We examined how we can utilize LINQ with the Guid.NewGuid(), or Random.Next() methods, as well as implementing the Fisher-Yates algorithm.

When randomizing arrays in C#, it is important to choose an appropriate algorithm that balances randomness and performance according to the specific requirements of the application we are implementing. Using benchmarks to measure performance and memory usage, we discovered the superiority of the method using the Fisher-Yates algorithm. 

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