Is there a built-in method to compare collections?
I would like to compare the contents of a couple of collections in my Equals method. I have a Dictionary and an IList. Is there a built-in method to do this?
Edited: I want to compare two Dictionaries and two ILists, so I think what equality means is clear - if the two dictionaries contain the same keys mapped to the same values, then they're equal.
Solution 1:
Enumerable.SequenceEqual
Determines whether two sequences are equal by comparing their elements by using a specified IEqualityComparer(T).
You can't directly compare the list & the dictionary, but you could compare the list of values from the Dictionary with the list
Solution 2:
As others have suggested and have noted, SequenceEqual
is order-sensitive. To solve that, you can sort the dictionary by key (which is unique, and thus the sort is always stable) and then use SequenceEqual
. The following expression checks if two dictionaries are equal regardless of their internal order:
dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
EDIT: As pointed out by Jeppe Stig Nielsen, some object have an IComparer<T>
that is incompatible with their IEqualityComparer<T>
, yielding incorrect results. When using keys with such an object, you must specify a correct IComparer<T>
for those keys. For example, with string keys (which exhibit this issue), you must do the following in order to get correct results:
dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
Solution 3:
In addition to the mentioned SequenceEqual, which
is true if two lists are of equal length and their corresponding elements compare equal according to a comparer
(which may be the default comparer, i.e. an overriden Equals()
)
it is worth mentioning that in .Net4 there is SetEquals on ISet
objects,
which
ignores the order of elements and any duplicate elements.
So if you want to have a list of objects, but they don't need to be in a specific order, consider that an ISet
(like a HashSet
) may be the right choice.
Solution 4:
Take a look at the Enumerable.SequenceEqual method
var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);
Solution 5:
This is not directly answering your questions, but both the MS' TestTools and NUnit provide
CollectionAssert.AreEquivalent
which does pretty much what you want.