LINQ Korzystanie z Max (), aby wybrać pojedynczy wiersz


98

Używam LINQ na IQueryable zwrócony z NHibernate i muszę wybrać wiersz z maksymalną wartością (wartościami) w kilku polach.

Uprościłem kawałek, na którym się trzymam. Muszę wybrać jeden wiersz z mojej tabeli z maksymalną wartością w jednym polu.

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

To jest niepoprawne, ale nie mogę opracować odpowiedniej formy.

A tak przy okazji, to, co faktycznie próbuję osiągnąć, to mniej więcej to:

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();

Zacząłem od powyższej lambdy, ale używałem LINQPad do wypróbowania składni wyboru Max ().

AKTUALIZACJA

Usunięcie GroupBy było kluczowe.

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();


@ M.Babcock w tym pytaniu była dobra odpowiedź: stackoverflow.com/a/6330485/444244
Boggin

Są znacznie lepsze niż to ...
M.Babcock

Spójrz na odpowiedź .
Sergey Brunov

@Serge Zgadzam się, że morelinq byłby najlepszy, ale obawiam się, że ten projekt ma przeszkody w dodawaniu nowych bibliotek.
Boggin

Odpowiedzi:


235

Nie rozumiem, dlaczego się tutaj grupujesz.

Spróbuj tego:

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

Alternatywnym podejściem, które można by powtórzyć tabletylko raz, byłoby:

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

Jest to przydatne, jeśli tablejest to IEnumerable<T>, że nie jest obecny w pamięci lub że jest obliczana na bieżąco.


1
Wyciągnąłem zgrupowanie i stwierdziłem, że mogę to uruchomić: from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
Boggin

1
Możesz także zagnieżdżać składnię lambda: table.First(x => x.Status == table.Max(x => x.Status))
Landon Poch,

15
@LandonPoch: To nie jest dobry pomysł, ponieważ obliczyłoby to maksymalne N razy, gdzie N to liczba elementów w table.
Daniel Hilgarth,

2
@Daniel Hilgarth: Dobry chwyt! To faktycznie obliczyłoby maksimum na każdy wiersz w tabeli. Mój błąd.
Landon Poch


13

Możesz grupować według stanu i wybrać wiersz z największej grupy:

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

Pierwsza First()pobiera pierwszą grupę (zestaw wierszy o największym statusie); druga First()otrzymuje pierwszy wiersz w tej grupie.
Jeśli stan jest zawsze unqiue można zastąpić drugą First()z Single().


7

Odpowiadając na pierwsze pytanie, jeśli chcesz wziąć kilka wierszy pogrupowanych według określonych kryteriów z drugą kolumną o maksymalnej wartości, możesz zrobić coś takiego:

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

Jeszcze jeden przykład:

Podążać:

 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);

Równa się:

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

-1

Po prostu w jednej linii:

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

Zauważ, że są dwie akcje. wewnętrzna akcja służy do znalezienia maksymalnej wartości, zewnętrzna akcja służy do uzyskania pożądanego obiektu.


Ta metoda została omówiona w komentarzach do przyjętej odpowiedzi, gdzie wskazano, że to zły pomysł.
Boggin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.