Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithm for testing inequality of ordered large collections

Ok, I need to test if two IEnumerable<T> are equal. The order of the elements is important, which means that:

{1, 2, 4, 1, 3} and {1, 2, 1, 3, 4} should not be equal.

I've seen a few answers on this site explaining how to do this with linq: for example, here

The problem is that I have to repeatedly test for equality of pretty big collections (thousands of elements) that have a high probability of not being equal, so performance is a factor to bear in mind. The way I see it, all the linq methods shown in the referred answer (Count or Except) need to, if I'm not mistaken, iterate through the whole collection which in the general case is not necessary.

I came up with this code, which works reasonably well (I think) and is fast enough. I was wondering if I'm missing some obvious built in way of doing this (I don't want to reinvent the wheel here if possible.)

 public static bool IsEqualTo<T>(this IEnumerable<T> inner, IEnumerable<T> other) where T: IEquatable<T>
 {
     if (inner == null)
         throw new ArgumentNullException();

     if (object.ReferenceEquals(inner, other))
         return true;

     if (object.ReferenceEquals(other, null))
         return false;

     using (var innerEnumerator = inner.GetEnumerator())
     using (var otherEnumerator = other.GetEnumerator())
     {
         while (innerEnumerator.MoveNext())
         {
             if (!otherEnumerator.MoveNext() || !innerEnumerator.Current.Equals(otherEnumerator.Current))
                return false;
         }

         return !otherEnumerator.MoveNext();
     }
 }
like image 222
InBetween Avatar asked Oct 16 '14 17:10

InBetween


1 Answers

Basically you are looking to short-circuit the evaluation when an element isn't found.

IEnumerable.SequenceEqual (MSDN) already does this; proved out by the implementation in: http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs (line 806)

When order is important, you should be able to write a simple while loop:

int i = 0;
int aCount = a.Count(); //Use `IList` so you can use the property for efficiency
int bCount = b.Count(); //Use `IList` so you can use the property for efficiency

if (aCount != bCount)
    return false;

while (a.ElementAt(i) == b.ElementAt(i))
   i++;

return i == aCount;

Your function does basically the same thing, and would work fine.

like image 134
BradleyDotNET Avatar answered Nov 02 '22 06:11

BradleyDotNET