Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>It turns out Microsoft already has this covered in its testing framework: <a href="http://msdn.microsoft.com/en-us/library/ms243779.aspx" rel="noreferrer">CollectionAssert.AreEquivalent</a> </p> <blockquote> <p>Remarks</p> <p>Two collections are equivalent if they have the same elements in the same quantity, but in any order. Elements are equal if their values are equal, not if they refer to the same object.</p> </blockquote> <p>Using reflector, I modified the code behind AreEquivalent() to create a corresponding equality comparer. It is more complete than existing answers, since it takes nulls into account, implements IEqualityComparer and has some efficiency and edge case checks. plus, it's <em>Microsoft</em> :)</p> <pre><code>public class MultiSetComparer&lt;T&gt; : IEqualityComparer&lt;IEnumerable&lt;T&gt;&gt; { private readonly IEqualityComparer&lt;T&gt; m_comparer; public MultiSetComparer(IEqualityComparer&lt;T&gt; comparer = null) { m_comparer = comparer ?? EqualityComparer&lt;T&gt;.Default; } public bool Equals(IEnumerable&lt;T&gt; first, IEnumerable&lt;T&gt; second) { if (first == null) return second == null; if (second == null) return false; if (ReferenceEquals(first, second)) return true; if (first is ICollection&lt;T&gt; firstCollection &amp;&amp; second is ICollection&lt;T&gt; secondCollection) { if (firstCollection.Count != secondCollection.Count) return false; if (firstCollection.Count == 0) return true; } return !HaveMismatchedElement(first, second); } private bool HaveMismatchedElement(IEnumerable&lt;T&gt; first, IEnumerable&lt;T&gt; second) { int firstNullCount; int secondNullCount; var firstElementCounts = GetElementCounts(first, out firstNullCount); var secondElementCounts = GetElementCounts(second, out secondNullCount); if (firstNullCount != secondNullCount || firstElementCounts.Count != secondElementCounts.Count) return true; foreach (var kvp in firstElementCounts) { var firstElementCount = kvp.Value; int secondElementCount; secondElementCounts.TryGetValue(kvp.Key, out secondElementCount); if (firstElementCount != secondElementCount) return true; } return false; } private Dictionary&lt;T, int&gt; GetElementCounts(IEnumerable&lt;T&gt; enumerable, out int nullCount) { var dictionary = new Dictionary&lt;T, int&gt;(m_comparer); nullCount = 0; foreach (T element in enumerable) { if (element == null) { nullCount++; } else { int num; dictionary.TryGetValue(element, out num); num++; dictionary[element] = num; } } return dictionary; } public int GetHashCode(IEnumerable&lt;T&gt; enumerable) { if (enumerable == null) throw new ArgumentNullException(nameof(enumerable)); int hash = 17; foreach (T val in enumerable.OrderBy(x =&gt; x)) hash = hash * 23 + (val?.GetHashCode() ?? 42); return hash; } } </code></pre> <p>Sample usage:</p> <pre><code>var set = new HashSet&lt;IEnumerable&lt;int&gt;&gt;(new[] {new[]{1,2,3}}, new MultiSetComparer&lt;int&gt;()); Console.WriteLine(set.Contains(new [] {3,2,1})); //true Console.WriteLine(set.Contains(new [] {1, 2, 3, 3})); //false </code></pre> <p>Or if you just want to compare two collections directly:</p> <pre><code>var comp = new MultiSetComparer&lt;string&gt;(); Console.WriteLine(comp.Equals(new[] {"a","b","c"}, new[] {"a","c","b"})); //true Console.WriteLine(comp.Equals(new[] {"a","b","c"}, new[] {"a","b"})); //false </code></pre> <p>Finally, you can use your an equality comparer of your choice:</p> <pre><code>var strcomp = new MultiSetComparer&lt;string&gt;(StringComparer.OrdinalIgnoreCase); Console.WriteLine(strcomp.Equals(new[] {"a", "b"}, new []{"B", "A"})); //true </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload