C# LINQ: Get items with max price
Asked Answered
A

5

7

I have a list of my objects:

class MyObj
{
    public String Title { get; set; }
    public Decimal Price { get; set; }
    public String OtherData { get; set; }
}

var list = new List<MyObj> {
 new MyObj { Title = "AAA", Price = 20, OtherData = "Z1" },
 new MyObj { Title = "BBB", Price = 20, OtherData = "Z2" },
 new MyObj { Title = "AAA", Price = 30, OtherData = "Z5" },
 new MyObj { Title = "BBB", Price = 10, OtherData = "Z10" },
 new MyObj { Title = "CCC", Price = 99, OtherData = "ZZ" }
};

What is the best way to get list with unique Title and MAX(Price). Resulting list needs to be:

var ret = new List<MyObj> {
 new MyObj { Title = "BBB", Price = 20, OtherData = "Z2" },
 new MyObj { Title = "AAA", Price = 30, OtherData = "Z5" },
 new MyObj { Title = "CCC", Price = 99, OtherData = "ZZ" }
};
Audient answered 25/5, 2011 at 11:7 Comment(0)
M
17

Well, you could do:

var query = list.GroupBy(x => x.Title)
                .Select(group =>
                {
                    decimal maxPrice = group.Max(x => x.Price);
                    return group.Where(x => x.Price == maxPrice)
                                .First();
                };

If you need LINQ to SQL (where you can't use statement lambdas) you could use:

var query = list.GroupBy(x => x.Title)
       .Select(group => group.Where(x => x.Price == group.Max(y => y.Price))
                             .First());

Note that in LINQ to Objects that would be less efficient as in each iteration of Where, it would recompute the maximum price.

Adjust the .First() part if you want to be able return more than one item with a given name if they both have the same price.

Within LINQ to Objects you could also use MoreLINQ's MaxBy method:

var query = list.GroupBy(x => x.Title)
                .Select(group => group.MaxBy(x => x.Price));
Martres answered 25/5, 2011 at 11:9 Comment(2)
Thanks for perfect explanation :)Audient
Dude, even though this is old, it just helped me out perfectly! You are so awesome in roman times they would have built temples to worship you.....then probably killed you because they were superstitious fickle people back then.Melyndamem
G
2
var ret = list.GroupBy(x => x.Title)
              .Select(g => g.Aggregate((a, x) => (x.Price > a.Price) ? x : a));

(And if you need the results to be a List<T> rather than an IEnumerable<T> sequence then just tag a ToList call onto the end.)

Gordongordy answered 25/5, 2011 at 11:13 Comment(0)
Z
1
var ret = list.OrderByDescending(x => x.Price).GroupBy(x => x.Title).Select(@group => @group.ElementAt(0)).ToList();

this should do it.

Zilvia answered 25/5, 2011 at 11:25 Comment(0)
S
0

Would like to mention that

var query = list.GroupBy(x => x.Title)
       .Select(group => group.Where(x => x.Price == group.Max(y => y.Price))
       .First());

Should be

var query = list.GroupBy(x => x.Title)
       .First(group => group.Where(x => x.Price == group.Max(y => y.Price)));

I like the Richard solution to greatest-n-per-group problem.

var query = list
    .OrderByDescending(o => o.Price)    //set ordering
    .GroupBy(o => o.Title)              //set group by
    .Select(o => o.First());            //take the max element

However it needs to be slightly modified

var query = list
    .OrderByDescending(o => o.Price)                       //set ordering
    .GroupBy(o => o.Title)                                 //set group by
    .Select(o => o.Where(k => k.Price == o.First().Price)) //take max elements
Sunburn answered 9/9, 2014 at 10:37 Comment(0)
K
0

Usinng MaxBy will make it simple.

var list = list.GroupBy(g => g.Title)
           .Select(s => 
           {
              return s.MaxBy(x => x.Price);
           }).ToList();
Kreda answered 10/1 at 8:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.