Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: Compare contents of two IEnumerables

Tags:

c#

linq

Is there a built in linq method thing I can use to find out if two sequences contains the same items, not taking the order into account?

For example:

{1, 2, 3} == {2, 1, 3} {1, 2, 3} != {2, 1, 3, 4} {1, 2, 3} != {1, 2, 4} 

You have the SequenceEquals, but then I would have to Order both sequences first, wouldn't I?

like image 753
Svish Avatar asked Mar 10 '09 13:03

Svish


2 Answers

There are quite a few ways. Assume A and B is IEnumerable.

!A.Except(B).Any() && !B.Except(A).Any() A.Count() == B.Count() && A.Intersect(B).Count() == B.Count() etc 
like image 73
leppie Avatar answered Sep 23 '22 14:09

leppie


If you don't care about duplicates (i.e. you'd consider {1, 2, 3} to be equal to {1, 2, 3, 2}) then:

new HashSet<int>(A).SetEquals(B) 

(Or whatever type is the element type instead of int).

Otherwise:

public static bool SequenceEqualUnordered<T>(IEnumerable<T> first, IEnumerable<T> second) {     if (first == null)         return second == null; // or throw if that's more appropriate to your use.     if (second == null)         return false;   // likewise.     var dict = new Dictionary<T, int>(); // You could provide a IEqualityComparer<T> here if desired.     foreach(T element in first)     {         int count;         dict.TryGetValue(element, out count);         dict[element] = count + 1;     }     foreach(T element in second)     {         int count;         if (!dict.TryGetValue(element, out count))             return false;         else if (--count == 0)             dict.Remove(element);         else             dict[element] = count;     }     return dict.Count == 0; } 

Keep a tally of each element in the first sequence, then check the second against it. The moment you have one too many in the second sequence you can return false, otherwise if you have nothing left in the dictionary of tallies they are equal, or false if there's any elements left.

Rather than the two O(n log n) sorts of using OrderBy() followed by the O(n) comparison, you've an O(n) operation building the set of tallies, and an O(n) check against it.

like image 41
Jon Hanna Avatar answered Sep 23 '22 14:09

Jon Hanna