Comparing arrays in C#

C#Arrays

C# Problem Overview


I am trying to compare two arrays with each other. I tried this code and got the following errors.

static bool ArraysEqual(Array a1, Array a2)
{
    if (a1 == a2)
        return true;

    if (a1 == null || a2 == null)
        return false;

    if (a1.Length != a2.Length)
        return false;

    IList list1 = a1, list2 = a2; //error CS0305: Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments
    for (int i = 0; i < a1.Length; i++)
    {
        if (!Object.Equals(list1[i], list2[i])) //error CS0021: Cannot apply indexing with [] to an expression of type 'IList'(x2)
            return false;
    }
    return true;
}

Why do I get that error? I went for a low-tech solution and did this which works fine, but I need to copy/paste it several times for each type.

static bool ArraysEqual(byte[] a1, byte[] a2)
{
    if (a1 == a2)
        return true;

    if (a1 == null || a2 == null)
        return false;

    if (a1.Length != a2.Length)
        return false;

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

C# Solutions


Solution 1 - C#

Providing that you have LINQ available and don't care too much about performance, the easiest thing is the following:

var arraysAreEqual = Enumerable.SequenceEqual(a1, a2);

In fact, it's probably worth checking with Reflector or ILSpy what the SequenceEqual methods actually does, since it may well optimise for the special case of array values anyway!

Solution 2 - C#

"Why do i get that error?" - probably, you don't have "using System.Collections;" at the top of the file - only "using System.Collections.Generic;" - however, generics are probably safer - see below:

static bool ArraysEqual<T>(T[] a1, T[] a2)
{
    if (ReferenceEquals(a1,a2))
        return true;

    if (a1 == null || a2 == null)
        return false;

    if (a1.Length != a2.Length)
        return false;

    EqualityComparer<T> comparer = EqualityComparer<T>.Default;
    for (int i = 0; i < a1.Length; i++)
    {
        if (!comparer.Equals(a1[i], a2[i])) return false;
    }
    return true;
}

Solution 3 - C#

For .NET 4.0 and higher, you can compare elements in array or tuples using the StructuralComparisons type:

object[] a1 = { "string", 123, true };
object[] a2 = { "string", 123, true };
        
Console.WriteLine (a1 == a2);        // False (because arrays is reference types)
Console.WriteLine (a1.Equals (a2));  // False (because arrays is reference types)
        
IStructuralEquatable se1 = a1;
//Next returns True
Console.WriteLine (se1.Equals (a2, StructuralComparisons.StructuralEqualityComparer)); 

Solution 4 - C#

Recommending SequenceEqual is ok, but thinking that it may ever be faster than usual for(;;) loop is too naive.

Here is the reflected code:

public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, 
	IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
	if (comparer == null)
	{
		comparer = EqualityComparer<TSource>.Default;
	}
	if (first == null)
	{
		throw Error.ArgumentNull("first");
	}
	if (second == null)
	{
		throw Error.ArgumentNull("second");
	}
	using (IEnumerator<TSource> enumerator = first.GetEnumerator())		
	using (IEnumerator<TSource> enumerator2 = second.GetEnumerator())
	{
		while (enumerator.MoveNext())
		{
			if (!enumerator2.MoveNext() || !comparer.Equals(enumerator.Current, enumerator2.Current))
			{
				return false;
			}
		}
		if (enumerator2.MoveNext())
		{
			return false;
		}
	}
	return true;
}

As you can see it uses 2 enumerators and fires numerous method calls which seriously slow everything down. Also it doesn't check length at all, so in bad cases it can be ridiculously slower.

Compare moving two iterators with beautiful

if (a1[i] != a2[i])

and you will know what I mean about performance.

It can be used in cases where performance is really not so critical, maybe in unit test code, or in cases of some short list in rarely called methods.

Solution 5 - C#

SequenceEqual can be faster. Namely in the case where almost all of the time, both arrays have indeed the same length and are not the same object.

It's still not the same functionality as the OP's function, as it won't silently compare null values.

Solution 6 - C#

I know this is an old topic, but I think it is still relevant, and would like to share an implementation of an array comparison method which I feel strikes the right balance between performance and elegance.

static bool CollectionEquals<T>(ICollection<T> a, ICollection<T> b, IEqualityComparer<T> comparer = null)
{
    return ReferenceEquals(a, b) || a != null && b != null && a.Count == b.Count && a.SequenceEqual(b, comparer);
}

The idea here is to check for all of the early out conditions first, then fall back on SequenceEqual. It also avoids doing extra branching and instead relies on boolean short-circuit to avoid unecessary execution. I also feel it looks clean and is easy to understand.

Also, by using ICollection for the parameters, it will work with more than just arrays.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser34537View Question on Stackoverflow
Solution 1 - C#NoldorinView Answer on Stackoverflow
Solution 2 - C#Marc GravellView Answer on Stackoverflow
Solution 3 - C#Yuliia AshomokView Answer on Stackoverflow
Solution 4 - C#Valentin KuzubView Answer on Stackoverflow
Solution 5 - C#ImiView Answer on Stackoverflow
Solution 6 - C#XavierView Answer on Stackoverflow