2010-01-25 2 views
16

У меня есть массив классов со свойством Date, т.е .:Найти минимальную и максимальную дату в массиве с помощью LINQ?

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

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

я должен найти (минимум) earliest и latest (максимум) дат в этом массиве.

Как это сделать с помощью LINQ?

+1

"эффективный" и "оптимальные" нужен контекст. Вам скорее нравится алгоритм, который эффективен в отношении пространства (использование памяти, размер кода) или время (время выполнения, время компиляции)? – EricSchaefer

ответ

38

Если вы хотите, чтобы найти самую раннюю или последний Дату:

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

Enumerable.Min, Enumerable.Max


Если вы хотите, чтобы найти запись с первой или последней датой:

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

См.: How to use LINQ to select object with minimum or maximum property value

+3

Определенно самый читаемый способ пойти. С точки зрения чистой эффективности, которая не была бы самой эффективной. Я сомневаюсь, что этот фрагмент кода будет узким местом. –

+0

@ Keith Rousseau: Почему вы думаете, что это не было бы «самым эффективным»? –

+4

@drj: Итерирует массив дважды. Тем не менее, такая же сложность, постоянный фактор удвоилась. – Joey

12

старая школа решение без 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, для downvoter: исходный quetion был: 'with C#', и был отредактирован до 'с LINQ' – Natrium

+0

На самом деле вы запутались: (minDate> r.Date) и (maxDate abatishchev

+1

@abatishchev: вы абсолютно правы, и я исправил это. – Natrium

1

Использование лямбда-выражений:

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]; 
    } 
} 

По существу:

  • Сортировка в новый список в порядке убывания даты
  • Выберите первый и последний элементы этого списка

UPDATE: Думая об этом, я не уверен, что это способ сделать это, если вы заботитесь на все о производительности, как сортировка всего списка приведет к гораздо больше сравнений, чем просто сканирование для наивысшие/самые низкие значения.

1

Я бы просто создал два свойства Min, Max, присвоив им значение первого элемента, добавляемого в массив, тогда каждый раз, когда вы добавляете новый элемент, просто проверяйте, меньше ли его DateTime, чем Min Max из них.

Его хороший и быстрый, и он будет намного быстрее, чем итерация через массив каждый раз, когда вам нужно получить Min Max.

3

Два в одном запросе LINQ (и один обхода):

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

Очень интересно! Не могли бы вы взглянуть на мой следующий вопрос. Http://stackoverflow.com/questions/2138391/how-to-rewrite-several-independent-linq-quries-into-single-one-using-aggregate. Я буду рад, если вы ответьте, и я мог бы принять это. – abatishchev

Смежные вопросы