Search code examples
c#listcomparisonequals

Compare two List<T> objects for equality, ignoring order


Yet another list-comparing question.

List<MyType> list1;
List<MyType> list2;

I need to check that they both have the same elements, regardless of their position within the list. Each MyType object may appear multiple times on a list. Is there a built-in function that checks this? What if I guarantee that each element appears only once in a list?

EDIT: Guys thanks for the answers but I forgot to add something, the number of occurrences of each element should be the same on both lists.


Solution

  • If you want them to be really equal (i.e. the same items and the same number of each item), I think that the simplest solution is to sort before comparing:

    Enumerable.SequenceEqual(list1.OrderBy(t => t), list2.OrderBy(t => t))
    

    Edit:

    Here is a solution that performs a bit better (about ten times faster), and only requires IEquatable, not IComparable:

    public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2) {
      var cnt = new Dictionary<T, int>();
      foreach (T s in list1) {
        if (cnt.ContainsKey(s)) {
          cnt[s]++;
        } else {
          cnt.Add(s, 1);
        }
      }
      foreach (T s in list2) {
        if (cnt.ContainsKey(s)) {
          cnt[s]--;
        } else {
          return false;
        }
      }
      return cnt.Values.All(c => c == 0);
    }
    

    Edit 2:

    To handle any data type as key (for example nullable types as Frank Tzanabetis pointed out), you can make a version that takes a comparer for the dictionary:

    public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer) {
      var cnt = new Dictionary<T, int>(comparer);
      ...