There are many different ways to compare arrays in C#. In this article, we are going to cover many of them, check some differences between each approach, and inspect a benchmark result for the fastest technique.

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

Let’s dive in.

Preparing the Environment

Before we start comparing arrays, we should create two arrays and fill them with some elements:

private static readonly int[] _firstArray = new int[] { 10, 9, 3, 8, 7 };
private static readonly int[] _secondArray = new int[] { 10, 9, 3, 8, 7 };

Some of our methods are going to use System.Linq and System.Collections namespaces, hance, it is necessary to add these namespaces if we are creating an application using .NET version earlier than 6.0:

using System.Collections;
using System.Linq;

Now that everything is ready. Let’s start.

Compare Arrays in C# Using == (Equality Operator)

To start with using the equality operator (==), we are going to create an EqualityOperator method:

public bool EqualityOperator(int[] firstArray, int[] secondArray)
{
    return firstArray == secondArray;
}

This method is going to receive the two arrays we want to compare as parameters. After checking if they are equal using ==, it is going to return a bool indicating the result of this operation.

It is important to mention that, as an array works as a reference type, this approach is not going to compare element by element of the arrays, but, if both arrays reference the same memory address. If both arrays are in the same memory address, we can assume they are the same array instance, however, with different variable names.

Compare Using Loop

In this approach, we are going to create a method with a for loop to iterate the entire array:

public bool ForLoop(int[] firstArray, int[] secondArray)
{
    if (firstArray.Length != secondArray.Length)
        return false;

    for (int i = 0; i < firstArray.Length; i++)
    {
        if (firstArray[i] != secondArray[i])
            return false;
    }

    return true;
}

Our method receives two arrays as parameters. Then, it compares if both arrays have the same length. If they have different lengths, they don’t share the same values as well.

After that, we can iterate through the entire array comparing if each index element has the same value in both arrays.

Once we find any different value, we can return false because we know that the arrays are different and we don’t need to go to the next iteration. However, if we finish the loop and don’t find any different value, we can return true indicating that the arrays are equal.

Compare Using Enumerable Class

The Enumerable class provides us with many methods to compare if two arrays are equal. However, it requires some attention on our side.

Enumerable.SequenceEqual

Let’s use Enumerable.SequenceEqual to compare two arrays:

return Enumerable.SequenceEqual(_firstArray, _secondArray);

This is a built-in method that iterates through the array comparing each element. Once we are using arrays of integers, and we know that int works as a value type, we don’t need to worry about how it is going to compare the elements.

Enumerable.SequenceEqual Using Arrays of Objects

If we are using arrays of objects, it is necessary to do some changes to compare the values. 

First, we are going to create an Article class to represent the elements of our array:

public class Article : IEqualityComparer<Article>
{
    public string? Title { get; set; }
    public DateTime LastUpdate { get; set; }
                
    public bool Equals(Article? first, Article? second)
    {
        return first?.Title == second?.Title && first?.LastUpdate == second?.LastUpdate;
    }

    public int GetHashCode(Article obj)
    {
        return base.GetHashCode();
    }
}

Note that our Article class inherits from IEqualityComparer and implements Equals and GetHashCode methods. The Equals method needs to compare each property from the first parameter with each property from the second parameter.

In this case, for the GetHashCode method, we just call the base implementation.

Now we are going to create two Article arrays and fill them with different instances, but equal data:

var firstArticle = new Article() { Title = "First Article", LastUpdate = new() };
var firstArticleCopy = new Article() { Title = "First Article", LastUpdate = new() };
var secondArticle = new Article() { Title = "Second Article", LastUpdate = new() };
var secondArticleCopy = new Article() { Title = "Second Article", LastUpdate = new() };

var articleArray = new Article[] { firstArticle, secondArticle };
var articleArrayCopy = new Article[] { firstArticleCopy, secondArticleCopy };

Finally, we can execute the Enumerable.SequenceEqual with our third parameter:

return Enumerable.SequenceEqual(articleArray, articleArrayCopy, new Article());

This third parameter (new Article()) defines the behavior to compare the values from each position of the array.

Enumerable.ReferenceEquals

Let’s see how to use the Enumerable.RefereceEquals method:

return ReferenceEquals(_firstArray, _secondArray);

Once the Enumerable class inherits from the object class, when we call this method, we are calling object.ReferenceEquals.

This call is going to return false if both arrays are not referencing the same memory address.

By default, it works similarly to the equality operator (==).

Enumerable.Equals

Let’s check how to use this built-in method to compare two arrays:

return Equals(_firstArray, _secondArray);

This method will return true if both arrays are referencing the same memory address. When we call this method, we are calling object.Equals

In this case, there’s no difference between calling one method or another because the main difference between Equals and ReferenceEquals is that Equals is a virtual method, so, we can override it in our classes. However, once we are talking about arrays, we can’t override either of them. That said, both method is going to check for reference equality.

Compare Using AsSpan().SequenceEqual() 

To use this approach, let’s create a AsSpanSequenceEqual method:

public bool AsSpanSequenceEqual(int[] firstArray, int[] secondArray)
{
    return firstArray.AsSpan().SequenceEqual(secondArray);
}

First, we create a new instance of Span<int>, then, similar to the Enumerable.SequenceEqual, we call the SequenceEqual method. The difference is that this time we are not using the Enumerable class, but the MemoryExtension class.

Once our array contains the same elements in the same order, the method returns true, otherwise, false.

Compare Arrays in C# Using IStructuralEquatable 

Another way to compare two arrays is using the IStructuralEquatable interface:

IStructuralEquatable structuralEquatable = firstArray;
return structuralEquatable.Equals(secondArray, StructuralComparisons.StructuralEqualityComparer);

First, we need to transform our first array in a IStructuralEquatable and then, call the Equals method, sending our second array and StructuralComparisons.StructuralEqualityComparer as parameters. If the array contains the same values, it is going to return true, otherwise, false

Benchmark Comparison

Let’s implement a benchmark comparison to check which is the fastest way to compare arrays.

For this benchmark, we are going to write a FillElements method to populate two arrays with 1 million elements:

private void FillElements(int length)
{
    _firstArray = new int[length];
    _secondArray = new int[length];

    for (int i = 0; i < length; i++)
    {
        var value = new Random().Next(0, 1000);
        _firstArray[i] = value;
        _secondArray[i] = value;
    }
}

After running this benchmark, we can inspect these results:

| Method                    | Mean                | Error             | StdDev             | Median              | 
|-------------------------- |--------------------:|------------------:|-------------------:|--------------------:| 
| EnumerableReferenceEquals | 0.0515 ns           | 0.0303 ns         | 0.0672 ns          | 0.0102 ns           | 
| EqualityOperator          | 0.0520 ns           | 0.0300 ns         | 0.0702 ns          | 0.0147 ns           | 
| EnumerableEquals          | 2.9548 ns           | 0.0990 ns         | 0.2215 ns          | 2.9540 ns           | 
| AsSpanSequenceEqual       | 425,462.1829 ns     | 9,919.7472 ns     | 13,958.5551 ns     | 423,506.7871 ns     | 
| EnumerableSequenceEqual   | 441,896.0402 ns     | 8,699.9267 ns     | 15,687.7625 ns     | 438,269.9219 ns     | 
| ForLoop                   | 631,013.9293 ns     | 12,496.0988 ns    | 26,630.2053 ns     | 631,100.8789 ns     | 
| StructuralEquatable       | 158,638,399.4792 ns | 4,576,887.9185 ns | 13,205,368.1315 ns | 157,580,000.0000 ns |

It is good to mention that, the three fastest methods (EnumerableReferenceEquals, EqualityOperator, EnumerableEquals) are checking if the arrays are referencing the same instances and not element by element.

The StructuralEquatable is the slowest method, and it is taking us more than 158 million nanoseconds (0,15 seconds) to compare one million elements.

Among the methods that are comparing each element individually, AsSpanSequenceEqual and EnumerableSequenceEqual are the fastest approaches. Achieving less than 500 thousand nanoseconds. 

The manual implementation (ForLoop) takes us 631 000 nanoseconds (0.631 milliseconds).

Conclusion

In this article, we’ve learned that we have many different, built-in and manual, ways to compare arrays in C#. In some of them, we compare just the reference, others we compare value by value.

With the help of the benchmark, we’ve seen the time each method takes, and it can help us to decide which method to use in different scenarios.