2012-02-02 16 views
67

Sto usando LINQ su un IQueryable restituito da NHibernate e devo selezionare la riga con il valore/i massimo in un paio di campi.LINQ Utilizzo Max() per selezionare una singola riga

Ho semplificato il bit su cui mi sto attaccando. Devo selezionare una riga dalla mia tabella con il valore massimo in un campo.

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 

Questo non è corretto ma non riesco a trovare il modulo corretto.

BTW, quello che sto effettivamente cercando di realizzare è di circa questo:

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

Ho iniziato con il lambda sopra, ma ho usato LINQPad per cercare di capire la sintassi per la selezione del Max ().

UPDATE

Rimozione del GroupBy è stata la chiave.

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

possibile duplicato: http://stackoverflow.com/questions/1101841/linq-how-per-forma-max-on-a-property-of-all-objects-in-a-collection-and-ret –

+0

@ M.Babcock c'era una buona risposta abbastanza in basso in quella domanda: http: // StackOverflow.it/a/6330485/444244 – Boggin

+0

Ne esistono di migliori ... –

risposta

166

Non vedo perché stai raggruppando qui.

Prova questo:

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

Un approccio alternativo che potrebbe iterare table solo una volta sarebbe questo:

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

Questo è utile se table è un IEnumerable<T> che non è presente in memoria o che è calcolato al volo.

+1

Ho eliminato il raggruppamento e ho scoperto che potevo farlo funzionare: 'in User_Accounts dove u.Status == User_Accounts.Max (y => y.Status) select you' – Boggin

+1

Puoi anche nidificare la sintassi lambda: 'table.First (x => x.Status == table.Max (x => x.Status))' –

+10

@LandonPoch: Non è una buona idea, in quanto ciò calcola il numero massimo di volte in cui N è il numero di elementi in 'tabella'. –

11

È possibile raggruppare in base allo stato per selezionare una riga dalla grande gruppo:

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

La prima First() ottiene il primo gruppo (l'insieme di righe con lo stato più grande); il secondo First() ottiene la prima riga in quel gruppo.
Se lo stato è sempre non valido, è possibile sostituire il secondo First() con Single().

9

È anche possibile fare:

(from u in table 
orderby u.Status descending 
select u).Take(1); 
5

Affrontare la prima domanda, se è necessario prendere diverse file raggruppati per determinati criteri con l'altra colonna con valore massimo che si può fare qualcosa di simile:

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

Semplicemente in una sola riga:

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

Si noti che ci sono due azioni. l'azione interna è per trovare il valore massimo, l'azione esterna è per ottenere l'oggetto desiderato.

+0

Questo metodo è stato discusso nei commenti alla risposta accettata dove è stato sottolineato che era una cattiva idea. – Boggin