views:

1902

answers:

4

I am trying to compare two .NET arrays. Here is an obvious implementation for comparing arrays of bytes:

bool AreEqual(byte[] a, byte[] b){
    if(a.Length != b.Length)
        return false;
    foreach(int i = 0; i < a.Length; i++)
        if(a[i] != b[i])
            return false;

    return true;
}

A more refined approach can be seen here (via Google).

  1. What is the simplest way (using less code but readable) to compare two .NET arrays?
  2. What is the most efficient way compare two .NET arrays?
+10  A: 

You could use SequenceEqual:

string[] a = { "1", "2", "3" };
string[] b = { "1", "2", "3" };

bool areEqual = a.SequenceEqual(b); // true


string[] c = { "1", "2", "5" };
areEqual = a.SequenceEqual(c);      // false
CMS
+4  A: 

Kathy's approach seems a good one to me. I'd personally allow the comparer to be specified explicitly:

bool AreEqual<T>(T[] a, T[] b){
    return AreEqual(a, b, EqualityComparer<T>.Default);
}

bool AreEqual<T>(T[] a, T[] b, IEqualityComparer<T> comparer){
    if(a.Length != b.Length)
        return false;
    for(int i = 0; i < a.Length; i++)
        if(comparer.Equals(a[i], b[i])
            return false;

    return true;
}

SequenceEqual as mentioned by CMS is good, but due to its generality over IEnumerable<T> I don't think it can do the "early out" if the length aren't equal. (It's possible that it checks for both sequences implementing IList though, to check Count directly.) You could generalise a little more, to use IList<T>

bool AreEqual<T>(IList<T> a, IList<T> b, IEqualityComparer<T> comparer){
    if(a.Count != b.Count)
        return false;
    for(int i = 0; i < a.Count; i++)
        if(comparer.Equals(a[i], b[i])
            return false;

    return true;
}

The straight array version will probably be the most efficient - adding generality and abstraction usually hits performance, although whether it's significant will depend on your app.

Jon Skeet
Shouldn't the above code snippets have `if (!comparer.Equals(a[i], b[i]) return false` ? Did I just detect an anomaly in my universe :)
Gishu
A: 

Maybe something like this?

static bool AreEqual<T>(T[] a, T[] b) 
{
    bool areEqual = false ;
    T[] result = a.Intersect(b.AsEnumerable()).ToArray();
    areEqual = (result.Length == a.Length) && (result.Length == b.Length);
    return areEqual;
}

I am not sure of the performance hit on this one though.

EDIT

revised version taking into account Jon suggestions:

    static bool AreEqual<T>(T[] a, T[] b) 
    {
        return a.SequenceEqual(b);
    }
Igor Zelaya
If you can use LINQ and don't mind the performance hit over using arrays directly (and early out for differing lengths), SequenceEqual is the way forward.
Jon Skeet
This solution fails when there are duplicates: { 1, 1, 1} = { 1, 1, 1} returns false. It also doesn't take ordering into account: { 1, 2} != {2, 1} returns true.
Jon Skeet
@Jon Thanks for the insight.
Igor Zelaya
"{ 1, 2} != {2, 1} returns true" should mean that ordering *is* taken into account, right?
Vulcan Eager
I'm saying that ordering *should* be taking into account, but isn't. The two arrays should be seen to be different, but the original version of AreEqual in this answer returns true. Sorry for the confusion.
Jon Skeet
+1  A: 

SequenceEqual will also make sure a and b are instanciated But it will not have the length optimisation