I've been using LINQ and Lambda Expressions for a while, but I'm still not completely comfortable with every aspect of the feature.
So, while I was working on a project recently I needed to get a distinct list of objects based off of some property, and I ran across this code. It works, and I'm fine with that, but I'd like to understand the grouping mechanism. I don't like simply plugging code in and running away from the problem if I can help it.
Anyways the code is:
var listDistinct
=list.GroupBy(
i => i.value1,
(key, group) => group.First()
).ToList();
In the code sample above, you're first calling GroupBy
and passing it a lambda expression telling it to group by the property value1
. The second section of the code is causing the confusion.
I understand that key
is referencing value1
in the (key, group)
statement, but I'm still not wrapping my head around everything that's taking place.
What does the expression
list.GroupBy( i => i.value1, (key, group) => group.First())
do?
This creates a query which, when executed, analyzes the sequence list
to produce a sequence of groups, and then projects the sequence of groups into a new sequence. In this case, the projection is to take the first item out of each group.
The first lambda chooses the "key" upon which the groups are constructed. In this case, all items in the list which have the same value1
property are put in a group. The value that they share becomes the "key" of the group.
The second lambda projects from the sequence of keyed groups; it's as though you'd done a select
on the sequence of groups. The net effect of this query is to choose a set of elements from the list such that each element of the resulting sequence has a different value of the value1
property.
The documentation is here:
http://msdn.microsoft.com/en-us/library/bb549393.aspx
If the documentation is not clear, I am happy to pass along criticisms to the documentation manager.
This code uses
group
as the formal parameter of a lambda. Isn'tgroup
a reserved keyword?
No, group
is a contextual keyword. LINQ was added to C# 3.0, so there might have already been existing programs using group
as an identifier. These programs would be broken when recompiled if group
was made a reserved keyword. Instead, group
is a keyword only in the context of a query expression. Outside of a query expression it is an ordinary identifier.
If you want to call attention to the fact that it is an ordinary identifier, or if you want to use the identifier group
inside a query expression, you can tell the compiler "treat this as an identifier, not a keyword" by prefacing it with @
. Were I writing the code above I would say
list.GroupBy(
i => i.value1,
(key, @group) => @group.First())
to make it clear.
Are there other contextual keywords in C#?
Yes. I've documented them all here:
http://ericlippert.com/2009/05/11/reserved-and-contextual-keywords/
I would like to simplify this to a list of int
and how to do distinct in this list by using GroupBy
:
var list = new[] {1, 2, 3, 1, 2, 2, 3};
if you call GroupBy
with x => x
, you will get 3 groups with type:
IEnumerable<IEnumerable<int>>
{{1,1},{2,2,2},{3,3}}
The key of each group are: 1, 2, 3. And then, when calling group.First()
, it means you get first item of each group:
{1,1}: -> 1.
{2,2,2}: -> 2
{3,3} -> 3
So the final result is : {1, 2, 3}
Your case is similar with this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With