Using GroupBy and Max in LINQ Lambda Expressions

29,129

Solution 1

EDIT: Okay, now we've got a slightly clearer set of requirements (though still far from clearly written) the simplest approach would probably be:

var maxes = list.GroupBy(x => x.id2,
                         (key, xs) => xs.OrderByDescending(x => x.id1)
                                        .First()
                                        .value);

Unfortunately LINQ doesn't provide a simple way of getting "the element with the maximal value" (instead of the maximal value itself). I have a method in MoreLINQ which does this though, called MaxBy:

var maxes = list.GroupBy(x => x.id2,
                         (key, xs) => xs.MaxBy(x => x.id2).value);

Original answer (Grouping by id2, taking the maximum value)

I'm answering assuming you actually meant to group by id2 rather than id1, and you actually wanted the results of 12 and 87 rather than 6 and 87. In that case, you'd want:

var maxes = list.GroupBy(x => x.id2, (id, xs) => xs.Max(x => x.value));

Or (possibly simpler to understand):

var maxes = list.GroupBy(x => x.id2)
                .Select(xs => xs.Max(x => x.value));

Or:

var maxes = list.GroupBy(x => x.id2, x => x.value)
                .Select(values => values.Max());

Or:

var maxes = list.GroupBy(x => x.id2,     // Key selector
                         x => x.value,   // Element selector
                         (key, values) => values.Max()); // Result selector

Or even:

var maxes = list.GroupBy(x => x.id2)
                .Select(xs => xs.Select(x => x.value).Max());

As you can see, GroupBy has lots of overloads :)

Or you could use a query expression:

var maxes = from x in list
            group x.value by x.id2 into values
            select values.Max();

You shouldn't restrict yourself to either query expressions or the extension method version - it's important to understand both, so you can use whatever's most appropriate.

Solution 2

Apparently OP wants the Value with maximum Id1 within Id2:

Sample data:

public class Row
{
    public int Id1;
    public int Id2;
    public int Value;
}

List<Row> rows = new List<Row>(){
    new Row(){Id1=1,Id2=9,Value=12},
    new Row(){Id1=2,Id2=9,Value=6},
    new Row(){Id1=3,Id2=11,Value=8},
    new Row(){Id1=4,Id2=11,Value=87}
};

Solution:

List<int> res = rows.GroupBy(r => r.Id2)
                    .Select(g => g.OrderByDescending(i=>i.Id1).First().Value)
                    .ToList();
Share:
29,129
Pavel
Author by

Pavel

Updated on July 15, 2022

Comments

  • Pavel
    Pavel almost 2 years

    I have a collection, for example:

    **id1, id2, value**
       1    9    12
       2    9     6
       3    11    8
       4    11   87
    

    I want to use LINQ and get the following result:

    **value**
       6
       87
    

    P.S.

    id1 - select MAX;
    id2 - group column;
    

    I need an answer in the form of

    var result = list.GroupBy(x=>x.id2).select(s=>s.value);
    

    I hope for your help.