2010-01-25 17 views
16

Mam tablicę klas z nieruchomości, tj .: DateZnajdź minimalną i maksymalną datę w tablicy używając LINQ?

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

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

muszę znaleźć (minimum) earliest i latest (maksymalnie) dat w tej tablicy.

Jak mogę to zrobić, używając LINQ?

+1

"skuteczny" oraz "optymalne" potrzebują kontekst. Czy wolałbyś raczej algorytm, który jest wydajny pod względem przestrzeni (wykorzystanie pamięci, rozmiar kodu) lub czasu (czas pracy, czas kompilacji)? – EricSchaefer

Odpowiedz

38

Jeśli chcesz znaleźć najwcześniejszy lub ostatni Data:

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

Enumerable.Min, Enumerable.Max


Jeśli chcesz odnaleźć rekord najwcześniejszego lub najnowszej Data:

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

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

+3

Zdecydowanie najbardziej czytelna droga. Pod względem czystej wydajności, która nie byłaby najbardziej wydajna. Wątpię jednak, by ten kawałek kodu był wąskim gardłem. –

+0

@Keith Rousseau: Dlaczego uważasz, że nie byłoby to "najbardziej wydajne"? –

+4

@drj: To iteruje tablicę dwa razy. Jednakowa złożoność, stały czynnik podwoił się. – Joey

12

stare rozwiązanie szkoła bez 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, dla downvoter: pierwotny quetion był: 'z C#', i był edytowany do 'z LINQ' – Natrium

+0

W rzeczywistości, masz zmieszane: (minDate> r.Date) i (maxDate abatishchev

+1

@abatishchev: masz absolutną rację i poprawiłem to. – Natrium

1

Korzystanie z wyrażeń 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]; 
    } 
} 

Zasadniczo:

  • Sortuj do nowej listy w kolejności daty
  • Wybierz pierwszy i ostatni element tego wykazu

UPDATE: Myśląc o tym, że nie jestem pewien, że jest to sposób, aby to zrobić, jeśli w ogóle dbają o wydajność, jak sortowanie całą listę spowoduje wiele więcej niż tylko porównań skanowania dla najwyższe/najniższe wartości.

1

Po prostu utworzę dwie właściwości: Min, Max, przypisz im wartość pierwszego elementu dodawanego do tablicy, a następnie za każdym razem, gdy dodasz nowy element, po prostu sprawdź, czy jego DateTime jest mniejsze lub większe niż Min Max te.

To jest ładne i szybkie i będzie znacznie szybsze niż powtarzanie tablicy za każdym razem, gdy potrzebujesz min Max.

3

dwa w jednym zapytaniu LINQ (i jednego przeglądania):

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

Bardzo interesujące! Czy mógłbyś spojrzeć na moje następne pytanie http://stackoverflow.com/questions/2138391/how-to-rewrite-several-independent-linq-quries-single-one-using-aggregate Będę szczęśliwy, jeśli możesz odpowiedz na to i mogę to zaakceptować. – abatishchev

Powiązane problemy