LINQ: Determine if two sequences contain exactly the same elements

I need to determine if two sets contain exactly the same elements. The order does not matter.

For example, these two arrays should be considered equal:

IEnumerable<int> data = new []{ 3,5,6,9 }; IEnumerable<int> otherData = new []{ 6,5,9,3} 

One set cannot contain any elements that are not in another.

Can this be done using the built-in query operators? And what would be the most effective way to implement it, given that the number of elements can vary from a few to hundreds?

+57
c # linq
Nov 04 '09 at 11:57
source share
7 answers

If you want to treat arrays as β€œsets” and ignore order and duplicate elements, you can use the HashSet<T>.SetEquals :

 var isEqual = new HashSet<int>(first).SetEquals(second); 

Otherwise, the best option is probably to sort both sequences in the same way and use SequenceEqual to compare them.

+96
Nov 04 '09 at 12:06
source share

I suggest sorting both and doing a phased comparison.

 data.OrderBy(x => x).SequenceEqual(otherData.OrderBy(x => x)) 

I'm not sure how quickly the OrderBy implementation is implemented, but if it's O (n log n), then, as expected, the general algorithm will be O (n log n).

For some data cases, you can improve this by using the custom OrderBy implementation, which, for example, uses the count collation for O (n + k), where k is the size of the range in which the values ​​lie.

+40
Nov 04 '09 at 12:05
source share

If you might have duplicates (or if you want a solution that works better for longer lists), I would try something like this:

 static bool IsSame<T>(IEnumerable<T> set1, IEnumerable<T> set2) { if (set1 == null && set2 == null) return true; if (set1 == null || set2 == null) return false; List<T> list1 = set1.ToList(); List<T> list2 = set2.ToList(); if (list1.Count != list2.Count) return false; list1.Sort(); list2.Sort(); return list1.SequenceEqual(list2); } 

UPDATE: you guys are right. The Except () solution below should look like before crossing the street. And it has a lousy perf for longer listings. Ignore this sentence below !:-)

Here is an easy way to do this. Note that this assumes the lists have no duplicates.

 bool same = data.Except (otherData).Count() == 0; 
+3
Nov 04 '09 at 12:02
source share

I know this is an old question, but here is another way to do it

 IEnumerable<int> data = new[] { 3, 5, 6, 9 }; IEnumerable<int> otherData = new[] { 6, 5, 9, 3 }; data = data.OrderBy(d => d); otherData = otherData.OrderBy(d => d); data.Zip(otherData, (x, y) => Tuple.Create(x, y)).All(d => d.Item1 == d.Item2); 
+2
Aug 21 '15 at 18:39
source share
  • First check the length. If they are different, the sets are different.
  • you can do data.Intersect(otherData); and check that the length is identical.
  • OR, simplify the sorting of sets and scroll through them.
0
Nov 04 '09 at 12:03
source share

This should help:

  IEnumerable<int> data = new []{ 3,5,6,9 }; IEnumerable<int> otherData = new[] {6, 5, 9, 3}; if(data.All(x => otherData.Contains(x))) { //Code Goes Here } 
-one
Nov 04 '09 at 12:02
source share

First check if both datasets have the same number of items and check if all items in one collection are represented in another

  IEnumerable<int> data = new[] { 3, 5, 6, 9 }; IEnumerable<int> otherData = new[] { 6, 5, 9, 3 }; bool equals = data.Count() == otherData.Count() && data.All(x => otherData.Contains(x)); 
-one
Nov 15 '14 at 20:24
source share



All Articles