LINQ Verwenden Sie Max (), um eine einzelne Zeile auszuwählen

95

Ich verwende LINQ für ein von NHibernate zurückgegebenes IQueryable und muss die Zeile mit den Maximalwerten in einigen Feldern auswählen.

Ich habe das Stück, an dem ich festhalte, vereinfacht. Ich muss die eine Zeile aus meiner Tabelle mit dem Maximalwert in einem Feld auswählen.

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

Das ist falsch, aber ich kann nicht das richtige Formular finden.

Übrigens versuche ich eigentlich Folgendes zu erreichen:

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

Ich habe mit dem obigen Lambda begonnen, aber ich habe LINQPad verwendet, um die Syntax für die Auswahl von Max () zu erarbeiten.

AKTUALISIEREN

Das Entfernen des GroupBy war der Schlüssel.

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();
Boggin
quelle
Mögliches Duplikat: stackoverflow.com/questions/1101841/…
M.Babcock
@ M.Babcock gab es eine gute Antwort ziemlich weit unten in dieser Frage: stackoverflow.com/a/6330485/444244
Boggin
Es gibt viel bessere als das ...
M.Babcock
Schauen Sie sich die Antwort an .
Sergey Brunov
@Serge Ich stimme zu, dass Morelinq am besten wäre, aber ich befürchte, dass dieses Projekt das Hinzufügen neuer Bibliotheken behindert.
Boggin

Antworten:

230

Ich verstehe nicht, warum Sie sich hier gruppieren.

Versuche dies:

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

Ein alternativer Ansatz, der tablenur einmal wiederholt werden würde, wäre folgender:

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

Dies ist hilfreich, wenn tablees sich um ein Gerät handelt IEnumerable<T>, das nicht im Speicher vorhanden ist oder das im laufenden Betrieb berechnet wird.

Daniel Hilgarth
quelle
1
Ich nahm die Gruppierung heraus und stellte fest, dass ich sie zum from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
Laufen
1
Sie können auch die Lambda-Syntax verschachteln: table.First(x => x.Status == table.Max(x => x.Status))
Landon Poch
13
@ LandPoch: Das ist keine gute Idee, da dies das Maximum N-mal berechnen würde, wobei N die Anzahl der Elemente in ist table.
Daniel Hilgarth
2
@ Daniel Hilgarth: Guter Fang! Das würde in der Tat das Maximum pro Zeile in der Tabelle berechnen. Mein Fehler.
Landon Poch
17

Sie können auch tun:

(from u in table
orderby u.Status descending
select u).Take(1);
KAPIL SHARMA
quelle
13

Sie können nach Status gruppieren und eine Zeile aus der größten Gruppe auswählen:

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

Die erste First()erhält die erste Gruppe (die Menge der Zeilen mit dem größten Status); Die zweite First()erhält die erste Zeile in dieser Gruppe.
Wenn der Status immer eindeutig ist, können Sie den zweiten First()durch ersetzen Single().

SLaks
quelle
7

Bei der Beantwortung der ersten Frage können Sie Folgendes tun, wenn Sie mehrere nach bestimmten Kriterien gruppierte Zeilen mit der anderen Spalte mit dem Maximalwert aufnehmen müssen:

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;
Dmitry Komin
quelle
0

Mehr ein Beispiel:

Folgen:

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

Gleich:

 select t.*   from nametable t  where t.OrdSeq =
        (select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)
SantanaFire
quelle
-1

Einfach in einer Zeile:

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

Beachten Sie, dass es zwei Aktionen gibt. Die innere Aktion dient zum Ermitteln des Maximalwerts, die äußere Aktion zum Abrufen des gewünschten Objekts.

Shneor
quelle
Diese Methode wurde in den Kommentaren zur akzeptierten Antwort diskutiert, wo darauf hingewiesen wurde, dass es eine schlechte Idee war.
Boggin