2010-01-25 20 views
16

mi hanno una serie di classi con una proprietà Date, cioè .:Trova la data minima e massima nell'array usando LINQ?

class Record 
{ 
    public DateTime Date { get; private set; } 
} 

void Summarize(Record[] arr) 
{ 
    foreach (var r in arr) 
    { 
     // do stuff 
    } 
} 

devo trovare il (minimo) earliest ei latest (massimo) date in questo array.

Come posso farlo utilizzando LINQ?

+1

"efficace" e "ottimale" bisogno di un contesto. Dovresti preferire un algoritmo che sia efficiente per quanto riguarda lo spazio (utilizzo della memoria, dimensioni del codice) o il tempo (tempo di esecuzione, tempo di compilazione)? – EricSchaefer

risposta

38

Se si vuole trovare la prima data o al più tardi:

DateTime earliest = arr.Min(record => record.Date); 
DateTime latest = arr.Max(record => record.Date); 

Enumerable.Min, Enumerable.Max


Se si desidera trovare il record con la prima data o al più tardi:

Record earliest = arr.MinBy(record => record.Date); 
Record latest = arr.MaxBy(record => record.Date); 

Vedi: How to use LINQ to select object with minimum or maximum property value

+3

Sicuramente il modo più leggibile per andare. In termini di pura efficienza che non sarebbe il più efficiente. Dubito che questo pezzo di codice sarebbe un collo di bottiglia, però. –

+0

@Keith Rousseau: Perché ti fa pensare che questo non sarebbe il "più efficiente"? –

+4

@drj: itera l'array due volte. Stessa complessità, fattore costante raddoppiato, però. – Joey

12

soluzione vecchia scuola senza LINQ:

DateTime minDate = DateTime.MaxValue; 
DateTime maxDate = DateTime.MinValue; 
foreach (var r in arr) 
{ 
    if (minDate > r.Date) 
    { 
     minDate = r.Date; 
    } 
    if (maxDate < r.Date) 
    { 
     maxDate = r.Date; 
    } 
} 
+6

ok, per il downright: la quetion originale era: 'con C#', ed è stata modificata con 'con LINQ' – Natrium

+0

In effetti, hai confuso: (minDate> r.Date) e (maxDate abatishchev

+1

@abatishchev: hai assolutamente ragione e ho corretto questo. – Natrium

1

Uso delle espressioni lambda:

void Summarise(Record[] arr) 
{ 
    if (!(arr == null || arr.Length == 0)) 
    { 
     List<Record> recordList = new List<Record>(arr); 
     recordList.Sort((x,y) => { return x.Date.CompareTo(y.Date); }); 

     // I may have this the wrong way round, but you get the idea. 
     DateTime earliest = recordList[0]; 
     DateTime latest = recordList[recordList.Count]; 
    } 
} 

In sostanza:

  • Ordina in un nuovo elenco in ordine di data
  • Selezionare il primo e ultimo elemento di quell'elenco

UPDATE: Pensando a questo proposito, non sono sicuro che questo è il modo per farlo se si cura affatto di prestazioni, come l'ordinamento l'intero elenco si tradurrà in molti altri confronti non solo la scansione per la valori più alti/più bassi.

1

Vorrei solo creare due proprietà Min, Max, assegnare loro il valore del primo elemento aggiunto all'array, quindi ogni volta che aggiungi un nuovo elemento controlla se il suo DateTime è minore o maggiore del Min Max quelli.

È bello e veloce e sarà molto più veloce dell'iterazione attraverso l'array ogni volta che è necessario ottenere Min Max.

3

I due in una query LINQ (e uno trasversale):

arr.Aggregate(
    new { MinDate = DateTime.MaxValue, 
      MaxDate = DateTime.MaxValue }, 
    (accDates, record) => 
     new { MinDate = record.Date < accDates.MinDate 
         ? record.Date 
         : accDates.MinDate, 
       MaxDate = accDates.MaxDate < record.Date 
         ? record.Date 
         : accDates.MaxDate }); 
+0

Molto interessante! Potresti vedere la mia prossima domanda http://stackoverflow.com/questions/2138391/how-to-rewrite-several-independent-linq-quries-into-single-one-using-aggregate Sarò felice se tu potessi rispondi e potrei accettarlo. – abatishchev

Problemi correlati