0

Seems like How does HashSet Compare elements for equality, but different, because that question focusses on the IEqualityComparer used by the HashSet. I want to write an Equality Comparer that declares two hashsets to be equal if SetEquals returns true;

I have a class MyClass, and a special IEqualityComparer<MyClass> that compares by value: two objects of MyClass are equal if their properties have equal values.

I have created a HashSet<MyClass> that uses this EqualityComparer to check for equality. And I want to create a HashSetComparer (preferrably as a generic class) that returns equal if SetEquals would return true.

some code:

var someData = ..
var myClass1 = new MyClass(someData);
var myClass2 = new MyClass(someData);

Normally these objects are not equal (reference equality)

IQualityComparer<MyClass> defaultComparer = EqualityComparer<MyClass>.Default;
Assert.IsFalse(defaultComparer.Equals(myClass1, myClass2));

But if I use my EqualityCompare, the objects appear to be equal

IQualityComparer<MyClass> valueComparer = ...
Assert.IsTrue(valueComparer.Equals(myClass1, myClass2));

So the comparer works fine. Let's create some HashSets:

// two unequal MyClass object
MyClass my1 = ...
MyClass my2 = ...
Assert.IsFalse(valueComparer.Equals(my1, my2);

var sequence1 = new MyClass[] {my1, my2};
var sequence2 = new MyClass[] {my2, my1};
var sequence3 = new MyClass[] {my1, my1, my2, my1, my2, my2}

var set1 = new HashSet<MyClass>(sequence1, valueComparer);
var set2 = new HashSet<MyClass>(sequence2, valueComparer);
var set3 = new HashSet<MyClass>(sequence3, valueComparer);

All three sets will have two elements. One that equals my1, and one that equals my2, using the valueComparer. A hashSet has no defined set order.

Assert.IsTrue(set1.SetEquals(set2);
Assert.IsTrue(set1.SetEquals(set3);

I want to create an equality comparer that declares two sets to be equal if they have SetQual

The equal function is easy:

public bool Equals(HashSet<MyClass> x, HashSet<MyClass> y)
{
    if (x == null) return y == null;               // both x and y null
    if (y == null) return false;                   // y null, but x not null
    if (object.ReferenceEquals(x, y)) return true; // x and y same object
    if (x.GetType() != y.GetType()) return false;  // x and y different type

    return x.SetEquals(y);
}

But how to write a proper GetHashCode()? There is no guarantee about the order of enumerated elements

Rand Random
  • 7,300
  • 10
  • 40
  • 88
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • How about you impose an order for your calculation? However, it sounds very odd to me that you want to use a *mutable collection* as a key for anything, what do you intend to use the hash code for? – Lasse V. Karlsen Oct 18 '18 at 14:59
  • `GetHashCode` is not required to try very hard, it just needs to be equal for things that are equal and sufficiently different for things that are not (so as not to trigger degenerative O(n) behavior in lookups). A simple and likely sufficient approach is to `xor` the `.GetHashCode()` of all elements of the set. I'm with Lasse here in questioning the validity of this approach to begin with, though. – Jeroen Mostert Oct 18 '18 at 15:03
  • Testing collections for equality is an iffy proposition. It is code that needs to jump off the screen and slap you in the face every time you look at it. Never try to stick an O(n) operation under the floor mat. If you want to do this anyway then implement GetHashCount() by simply returning the HashSet<>.Count property. And triple-check that you never use it as a key in a Dictionary or add it to a HashSet since that now seems to work but rarely does in practice since it is mutable. – Hans Passant Oct 18 '18 at 15:43

0 Answers0