Compare if two sequences are equal

心不动则不痛 提交于 2019-12-02 06:28:09

问题


Before marking this as duplicate because of its title please consider the following short program:

static void Main()
{
    var expected = new List<long[]> { new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } };
    var actual = DoSomething();
    if (!actual.SequenceEqual(expected)) throw new Exception();
}

static IEnumerable<long[]> DoSomething()
{
    yield return new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
}

I have a method which returns a sequence of arrays of type long. To test it I wrote some test-code similar to that one within Main.

However I get the exception, but I don´t know why. Shouldn´t the expected sequence be comparable to the actually returned one or did I miss anything?

To me it looks as both the method and the epxected contain exactly one single element containing an array of type long, doesn´t it?

EDIT: So how do I achieve to not get the exception meaning to compare the elements within the enumeration to return equality?


回答1:


The actual problem is the fact that you're comparing two long[], and Enumerable.SequenceEquals will use an ObjectEqualityComparer<Int64[]> (you can see that by examining EqualityComparer<long[]>.Default which is what is being internally used by Enumerable.SequenceEquals), which will compare references of those two arrays, and not the actual values stored inside the array, which obviously aren't the same.

To get around this, you could write a custom EqualityComparer<long[]>:

static void Main()
{
    var expected = new List<long[]> 
                       { new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } };
    var actual = DoSomething();

    if (!actual.SequenceEqual(expected, new LongArrayComparer()))
        throw new Exception();
}

public class LongArrayComparer : EqualityComparer<long[]>
{
    public override bool Equals(long[] first, long[] second)
    {
        return first.SequenceEqual(second);
    }

    // GetHashCode implementation in the courtesy of @JonSkeet
    // from http://stackoverflow.com/questions/7244699/gethashcode-on-byte-array
    public override int GetHashCode(long[] arr)
    {
        unchecked
        {
            if (array == null)
            {
                return 0;
            }

            int hash = 17;
            foreach (long element in arr)
            {
                hash = hash * 31 + element.GetHashCode();
            }

            return hash;
        }
    }
}



回答2:


No, your sequences are not equal!

Lets remove the sequence bit, and just take what is in the first element of each item

var firstExpected = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
var firstActual = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
Console.WriteLine(firstExpected == firstActual); // writes "false"

The code above is comparing two separate arrays for equality. Equality does not check the contents of arrays it checks the references for equality.

Your code using SequenceEquals is, essentially, doing the same thing. It checks the references in each case of each element in an enumerable.




回答3:


SequenceEquals tests for the elements within the sequences to be identical. The elements within the enumerations are of type long[], so we actually compare two different arrays (containing the same elements however) against each other which is obsiously done by comparing their references instead of their actual value .

So what we actually check here is this expected[0] == actual[0] instead of expected[0].SequqnceEquals(actual[0])

This is obiosuly returns false as both arrays share different references.

If we flatten the hierarchy using SelectMany we get what we want:

if (!actual.SelectMany(x => x).SequenceEqual(expected.SelectMany(x => x))) throw new Exception();

EDIT:

Based on this approach I found another elegant way to check if all the elements from expected are contained in actual also:

if (!expected.All(x => actual.Any(y => y.SequenceEqual(x)))) throw new Exception();

This will search if for ever sub-list within expected there is a list within actual that is sequentially identical to the current one. This seems much smarter to be as we do not need any custom EqualityComparer and no weird hashcode-implementation.



来源:https://stackoverflow.com/questions/34046578/compare-if-two-sequences-are-equal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!