LINQ Використовуючи Max () для виділення одного рядка


95

Я використовую LINQ для IQueryable, повернутого з NHibernate, і мені потрібно вибрати пару з максимальним значенням у кількох полях.

Я спростив біт, на якому я дотримуюся. Мені потрібно вибрати один рядок зі своєї таблиці з максимальним значенням в одному полі.

var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }

from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u

Це неправильно, але я не можу скласти правильну форму.

До речі, я насправді намагаюся досягти приблизно такого:

var clientAddress = this.repository.GetAll()
    .GroupBy(a => a)
    .SelectMany(
            g =>
            g.Where(
                a =>
                a.Reference == clientReference && 
                a.Status == ClientStatus.Live && 
                a.AddressReference == g.Max(x => x.AddressReference) && 
                a.StartDate == g.Max(x => x.StartDate)))
    .SingleOrDefault();

Я розпочав з вищезазначеної лямбди, але використовував LINQPad, щоб спробувати виробити синтаксис для вибору Max ().

ОНОВЛЕННЯ

Видалення GroupBy було ключовим.

var all = this.repository.GetAll();

var address = all
            .Where(
                a =>
                a.Reference == clientReference && 
                a.Status == ClientStatus.Live && 
                a.StartDate == all.Max(x => x.StartDate) &&
                a.AddressReference == all.Max(x => x.AddressReference))
            .SingleOrDefault();

можливо дублікат: stackoverflow.com/questions/1101841 / ...
M.Babcock

@ M.Babcock був хороший відповідь досить далеко вниз в цьому питанні: stackoverflow.com/a/6330485/444244
Boggin

Є набагато кращі, ніж це ...
M.Babcock 02

Подивіться на відповідь .
Сергій Брунов 02

@Serge Я погоджуюся, що найкращим буде morelinq , але я боюся, що цей проект перешкоджає додаванню нових бібліотек.
Боггін

Відповіді:


230

Я не бачу, чому ви тут групуєтесь.

Спробуйте це:

var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);

Альтернативний підхід, який повторюється tableлише один раз, буде таким:

var result = table.OrderByDescending(x => x.Status).First();

Це корисно, якщо tableтаке IEnumerable<T>, якого немає в пам'яті або яке обчислюється на льоту.


1
Я вийняв групування і виявив, що зможу це from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
запустити

1
Ви також можете вкласти синтаксис лямбда: table.First(x => x.Status == table.Max(x => x.Status))
Лендон Поч,

13
@LandonPoch: Це не гарна ідея, оскільки це дозволить обчислити максимум N разів, причому N - кількість елементів у table.
Даніель Хілгарт,

2
@Daniel Hilgarth: Хороший улов! Це насправді розрахувало б максимум для кожного рядка таблиці. Моє ліжко.
Лендон Поч,


13

Ви можете згрупувати за статусом і вибрати рядок із найбільшої групи:

table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();

Перша First()отримує першу групу (набір рядків з найбільшим статусом); другий First()отримує перший рядок у цій групі.
Якщо стан завжди не відповідає, ви можете замінити другий First()на Single().


7

Звертаючись до першого питання, якщо вам потрібно взяти кілька рядків, згрупованих за певними критеріями, з іншим стовпцем з максимальним значенням, ви можете зробити щось подібне:

var query =
    from u1 in table
    join u2 in (
        from u in table
        group u by u.GroupId into g
        select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
    ) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
    select u1;

0

Ще один приклад:

Дотримуйтесь:

 qryAux = (from q in qryAux where
            q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
            == q.FieldPk select pp.OrdSeq).Max() select q);

Дорівнює:

 select t.*   from nametable t  where t.OrdSeq =
        (select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)

-1

Просто в один рядок:

var result = table.First(x => x.Status == table.Max(y => y.Status));

Зверніть увагу, що існує дві дії. внутрішня дія - для пошуку максимального значення, зовнішня - для отримання бажаного об'єкта.


Цей метод обговорювався в коментарях до прийнятої відповіді, де вказувалося, що це погана ідея.
Боггін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.