Use IEnumerable<Foo>.Distinct
and implement your equality operator with the operator where the Baz
property is checked, and the HasBar
property HasBar
ignored if Baz
not equal. You can do this with &&
because if the left expression is false, the right expression is not evaluated.
Then a HasBar
based HasBar
with IEnumerable<Foo>.Where
.
If you do not want to clutter your Foo
object with the Equals
operator, or you need different Equals
implementations for different cases, then run a separate IEqualityComparer<Foo>
.
This also has the advantage that you can completely not check the HasBar
property when getting different values. If you miss a check in the class itself, it can cause subtle mistakes, because people can expect them to be equal. But with a well-known user mapping, it is unlikely that people will believe that it will ensure absolute equality.
Here is a sample code:
IEnumerable<Foo> selectedFoos = sampleDataSet .Distinct(new PerformantFooComparer()) .Where(f => f.HasBar); // ... private class PerformantFooComparer : IEqualityComparer<Foo> { public bool Equals(Foo x, Foo y) { bool isXNull = x == null; bool isYNull = y == null; return isXNull == isYNull && isXNull || ( x.Baz == y.Baz // && x.HasBar == y.HasBar // HasBar commented out to avoid performance overhead. // It is handled by a Where(foo => foo.HasBar) filter ); } public int GetHashCode(Foo obj) { if (obj == null) return 0; // See: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode int hash = 17; hash = hash * 23 + obj.Baz.GetHashCode(); // HasBar intentionally not hashed return hash; } }
source share