Why doesn't Linq provide a lambda parameter instead of IEqualityComparer <T>?
So, in things like GroupBy()
Linq, you can provide an implementation IEqualityComparer<T>
to help you compare objects. It seems, however, that it would be easier to just pass it to the lambda expression.
Example:
// current implementation
myCollection.GroupBy(c => c.Foo, c => c.Bar, new FooBarComparer());
// it seems easier to...
myCollection.GroupBy(c => c.Foo, c => c.Bar, (x, y) => x.Baz == y.Baz);
For a simple implementation IEqualityComparer<T>
:
public class FooBarComparer : IEqualityComparer<FooBar> {
public bool Equals(FooBar x, FooBar y) {
return x.Baz == y.Baz;
}
public int GetHashCode(FooBar obj) {
return obj.GetHashCode();
}
}
It seems like providing a lambda expression can be just as efficient. Like now, if I try to pass IEqualityComparer<T>
with a Linq query to the database, it fails because SQL Server (or whatever) doesn't know anything about my class. It seems like the lambda could be translated to SQL which can be used on the target database.
Is there a specific reason why this isn't provided as an option in Linq?
source to share
You will need two lambdas to GetHashCode
have an equivalent too. Also, it will work, yes. There are some LINQ methods that don't use hash codes, but use equality ( Enumerable.Contains
).
I assume this is just a standard API for equality that the entire BCL uses. You can easily convert between a delegate and a comparator by using a delegate-enabled comparison implementation or by converting myComparer.Equals
to a delegate.
It is not easy to drop a comparator expression to drop expressions into the database. GROUP BY
does not support this in SQL. This can certainly be made to work, but this is a niche use case (in fact, if a comparator expression for GroupBy
doesn't enforce an equality relationship, I'm not sure how that would turn out when translated to SQL).
source to share
To create an efficient GroupBy
/ Distinct
you will need two things:
- Equality comparator
- Hash generator for creating a hash dictionary
OR you can follow the C ++ route
- A comparator capable of ordering elements so that you can create a tree
If you only have an equality matcher, then the difficulty of doing GroupBy
is something like O (n ^ 2), because if you have 5 elements you need 5 + 4 + 3 + 2 + 1 comparisons, so n * ( n + 1) / 2 so 15. This is what a "good" library will never let you do (and no sane SQL server will ever!)
Now obviously the LINQ library could parse your equality lambda, see that it is
(x, y) => x.Baz == y.Baz
we see that it is symmetric, so that the left term and the right term have the form
x => x.Baz
and use that to generate hash and select comparator. But for now, it would be easier to do directly
myCollection.GroupBy(c => c.Foo.Baz)
Yes, what can you do :-)
And then,
myCollection.GroupBy(c => c.Foo.Baz, c => new { c.Foo, c.Bar })
.Select(c => new { Key = c.First().Foo, Values = c.Select(x => x.Bar) })
This is very similar to your intended GroupBy
(the only difference is that the values are in Values
IEnumerable<>
)
Now ... to use overloads with IEqualityComparer<T>
... as I wrote in the comments, I think they should be used with " overloads " that the LINQ provider can recognize as being different StringComparer.*
(for example StringComparer.OrdinalIgnoreCase
) and EqualityComparer<T>.Default
that is the default mapping.
source to share