Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing arrays content, difference of SequenceEqual and StructuralComparisons.StructuralEqualityComparer

Tags:

c#

.net

.net-4.0

I have 2 arrays :

        int[] arr1 = new int[] { 1, 2, 3 };
        int[] arr2 = new int[] { 1, 2, 3 };

I need to check if they are equal ( not by ref)

What is the difference between writing :

        Console.WriteLine(arr1.SequenceEqual(arr2)); //true

vs

        IStructuralEquatable eqArray1 = arr1;
        Console.WriteLine(eqArray1.Equals(arr2, StructuralComparisons.StructuralEqualityComparer));  //true

both returns True..

When should I use each ?

like image 713
Royi Namir Avatar asked Sep 30 '12 08:09

Royi Namir


3 Answers

The implementation of SequenceEqual is kind of similar::

using (IEnumerator<TSource> enumerator1 = first.GetEnumerator())
using (IEnumerator<TSource> enumerator2 = second.GetEnumerator())
{
    while (enumerator1.MoveNext())
    {
        if (!enumerator2.MoveNext() || !comparer.Equals(enumerator1.Current, enumerator2.Current))
        {
            return false;
        }
    }

    if (enumerator2.MoveNext())
    {
        return false;
    }
}

return true;

This default SequenceEqual method use default EqualityComparer<int>.Default for int which is value equality.

Array implement IStructuralEquatable with Equal method:

bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer)
{
    if (other == null) return false;

    if (!object.ReferenceEquals(this, other))
    {
        Array array = other as Array;
        if ((array == null) || (array.Length != this.Length))
        {
            return false;
        }
        for (int i = 0; i < array.Length; i++)
        {
            object x = this.GetValue(i);
            object y = array.GetValue(i);

            if (!comparer.Equals(x, y))
            {
                return false;
            }
        }
    }

    return true;
}

The IEqualityComparer from input parameter is used, in here you input StructruralEqualityComparer but int does not implement IStructruralEquatable, so it uses default comparer for int which is value equality.

But, needless to input StructruralEqualityComparer because int is not structural, you should just use:

(arr1 as IStructuralEquatable).Equals(arr2, EqualityComparer<int>.Default);

It still works. You should use StructruralEqualityComparer if item in array is structrural

So to sum up, the implementation for both is kind of the same, both iterate two array based on value equality of int to make comparison.

I would prefer the LINQ verson since it is more readable.

like image 108
cuongle Avatar answered Nov 15 '22 10:11

cuongle


I just had a related question and saw that this question was never actually answered properly. There is a difference between the structural and the sequence - the first comparison is deep and the second one is not.

This simple code demonstrates and produces True False:

int[][] ints1 = { new int[] { 3, 4 } };
int[][] ints2 = { new int[] { 3, 4 } };
Console.WriteLine(StructuralComparisons.
                          StructuralEqualityComparer.Equals(ints1, ints2));
Console.WriteLine(ints1.SequenceEqual(ints2));

The name "sequence" suggests one-dimensionalism so the name choice is appropriate.

like image 25
Mishax Avatar answered Nov 15 '22 09:11

Mishax


Standard equality checks in .NET uses EqualityComparer.Default for comparisons. For example dictionaries or SequenceEqual method you have written there uses EqualityComparer.Default by default. And that comparer either uses Equals(object) method or Equals(T) method in presence of IEquatable interface implementation.

But you can always give other comparers like StructuralComparisons.StructuralEqualityComparer to dictionaries or methods such as SequenceEqual.

So, the main difference between two methods is the equality check method they use. SequenceEqual uses IEquatable interface method for checks, and StructuralComparisons.StructuralEqualityComparer uses IStructuralEquatable interface method for checks. And as a result, default equality checks need two of the compared items to be the same type but StructuralEqualityComparer doesn't require them to be same type. As the name suggests it is supposed to compare contents.

like image 29
zahir Avatar answered Nov 15 '22 09:11

zahir