C # LINQ: Получить предметы с максимальной ценой - PullRequest
6 голосов
/ 25 мая 2011

У меня есть список моих объектов:

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" }
};

Как лучше всего получить список с уникальным Заголовком и МАКС (Цена). Результирующий список должен быть:

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" }
};

Ответы [ 4 ]

16 голосов
/ 25 мая 2011

Ну, вы могли бы сделать:

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

Если вам нужен LINQ to SQL (где вы не можете использовать лямбда-выражения), вы можете использовать:

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

Обратите внимание, что в LINQ to Objects, которые будут менее эффективными, как на каждой итерации Where, будет пересчитана максимальная цена.

Настройте часть .First(), если хотите иметь возможность вернуть более одного элемента с данным именем, если они оба имеют одинаковую цену.

В LINQ to Objects вы также можете использовать MoreLINQ MaxBy метод:

var query = list.GroupBy(x => x.Title)
                .Select(group => group.MaxBy(x => x.Price));
2 голосов
/ 25 мая 2011
var ret = list.GroupBy(x => x.Title)
              .Select(g => g.Aggregate((a, x) => (x.Price > a.Price) ? x : a));

(И если вам нужно, чтобы результаты были последовательностью List<T>, а не IEnumerable<T>, просто отметьте вызов ToList в конце.)

1 голос
/ 25 мая 2011
var ret = list.OrderByDescending(x => x.Price).GroupBy(x => x.Title).Select(@group => @group.ElementAt(0)).ToList();

это должно сделать это.

0 голосов
/ 09 сентября 2014

Хотелось бы отметить, что

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

Должно быть

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

Мне нравится решение Ричарда для наибольших чисел в группе .

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

Однако его нужно немного изменить

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
...