2009-12-18 5 views
6

У меня есть группа строк, сгруппированных по атрибуту MyID. Теперь мне нужна одна строка из каждой группы, где атрибут StatusDate является самым высоким в этой группе.LINQ: Получение строки с максимальным значением заданного атрибута

Это то, что я придумал.

rows.Select(x => x.Where(y => y.StatusDate == x.Max(z => z.StatusDate)).First()) 

С немного больше объяснения:

rows.Select(x => // x is a group 
    x.Where(y => // get all rows in that group where... 
       // the status date is equal to the largest 
       // status date in the group 
    y.StatusDate == x.Max(z => z.StatusDate) 
).First()) // and then get the first one of those rows 

Есть ли быстрее или более идиоматических способ сделать это?

+0

Почему вы выбираете все строки с самым большим DateTime, но только выбираете первый? Если вам не важно, какая «максимизированная» строка вы выберете, возможно, вы должны заменить x.Where (...). Сначала() с помощью x.Max (...). –

+0

@ Vlad: Добавьте это как ответ, и я приму это. Делает совершенный смысл. –

+1

'x.Max (...)' не вернет всю строку, хотя - только максимальное значение. –

ответ

15

Одним из вариантов было бы использовать:

rows.Select(x => x.OrderByDescending(y => y.StatusDate).First()); 

... и убедитесь, что Оптимизатор запросов знает, что он не действительно нужно сортировать все. (Это будет иметь катастрофические последствия в LINQ к объектам, но вы можете использовать MaxBy из MoreLINQ в этом случае :)

(Извинения для предыдущей версии. - Я не вполне понимал немного группирования)

+0

Немного не по теме, но ... Можете ли вы опубликовать пример или ссылку на место, где мы можем увидеть MoreLINQ в действии? Это 'MaxBy' действительно вызвало у меня восторг. –

+0

@Alex: Вы имеете в виду только образец кода? В этом случае это будет 'rows.Select (x => x.MaxBy (y => y.StartDate))' - но у нас нет «витрины» этих вещей, которые, возможно, нам следует ... –

+0

Это хороший вариант, но мне сложно сказать, какие результаты в более эффективном TSQL. Ваше собственное решение уже неплохо. Я бы запустил оба из них через отладчик, чтобы узнать, как выглядит сгенерированный TSQL, а затем запустить каждый через SQL Management Studio напрямую и взглянуть на планы выполнения и, возможно, даже запустить его через анализатор производительности и/или профилировщик тоже , –

0

Не знаете ли это Linq to SQL, но если это так, вы можете в качестве альтернативы выполнить функцию rank() в SQL (ранжировать каждую группу по дате, затем выбирать первую ранжированную строку из каждого), а затем вызывать это как хранимую процедуру из LINQ. Я думаю, что это вопрос, который становится более идиоматичным, поскольку люди сталкиваются с бестолками LINQ2SQL ...