2009-05-05 2 views
1

У меня есть небольшая проблема, когда я хочу найти следующий «активный» элемент в списке с linq. Затем следующий «активный» элемент определяется startDate и EndDate. Вот список примеров.Как получить следующий активный элемент в списке с LINQ

//-- Create Lists of turns  
    IList<Turn> turns= new List<Turn>(){ 
       new Turn(){Name = "Turn 1", StartDate = DateTime.Parse("2009-05-01"), EndDate = DateTime.Parse("2009-05-01") } 
     ,  new Turn(){Name = "Turn 2", StartDate = DateTime.Parse("2009-06-01"), EndDate = DateTime.Parse("2009-06-01") } 
     ,  new Turn(){Name = "Turn 3", StartDate = DateTime.Parse("2009-07-01"), EndDate = DateTime.Parse("2009-07-02") } 
     ,  new Turn(){Name = "Turn 4", StartDate = DateTime.Parse("2009-08-01"), EndDate = DateTime.Parse("2009-08-03") } 
    } 

//-- Get the next Turn by DateTime. 
DateTime toDay = DateTime.Parse("2009-06-02"); 

//-- Should return the "Turn 3" item... 
Turn turn = (from item in turns 
      where ..... 
      select turn).FirstOrDefault<Turn>(); 

Есть ли хорошее решение, чтобы найти следующий поворот, используя свойства startDate/endDate на Turn. Я попробовал сначала заказать список по startdate и найти First в списке, но я понял, что существует более «безопасный» способ получить его, чтобы он не нуждался в списке в правильном порядке, чтобы найти правильный Turn.

+0

У меня есть решение, но не могли бы вы уточнить условия, на которых можно выбрать подходящий поворот, пожалуйста? – Noldorin

ответ

0

Почему бы вам просто не получить первый элемент с датой начала после сегодняшнего дня? Я добавил сообщение об ошибке OrderBy(), чтобы убедиться, что список отсортирован. Если вы знаете, что он отсортирован, вы можете это исключить, конечно.

turns.OrderBy(t => t.StartDate).FirstOrDefault(t => t.StartDate > today); 

UPDATE

я пропустил свои последние строки. Да, вы можете сделать это, не сортируя список явно. Вы должны искать список для элемента с датой начала после сегодняшнего дня, а ther не должен быть элементом с датой начала после сегодняшнего дня, но до текущей позиции. Но это действительно замедлит поиск, потому что вы должны посмотреть на весь список для каждого элемента, делающего вещь O (n²).

turns.Single(t => 
    t.StartDate > today && 
    turns.All(u => u.StartDate <= today || u.StartDate > t.StartDate)) 

Это предполагает, что повороты не перекрываются. Если они перекрывают, вы должны использовать First вместо Single или добавить дополнительные ограничения, чтобы получить уникальный результат. И, наконец: используйте решение для сортировки - это решение отнюдь не безопаснее, чем сортировка и получение первого элемента.

+0

Я пробовал последнее утверждение, но это было очень медленно, мне кажется, мне нужно сначала отсортировать список и получить FirstOrDefault ... Похоже, что это самый простой способ получить то, что я хочу ... –

0

Я думаю, что вы просто хотите:

var turn = turns.SkipWhile(t => t.EndDate < today).FirstOrDefault(); 

Это возвратит первый поворот либо содержащий или после указанной даты today, что то, что вы, кажется, ищет. Вы также можете скачать следующие инструкции, относящиеся к вашему выбору: turns.

Редактировать: Похоже, я пропустил немного о вас, не желая сортировать список. Я все еще не совсем уверен в том, что вам нужно выбрать подходящий поворот, который позволит мне улучшить запрос.

+0

Это может быть неудачно, если список не сортирован - вы просто возвращаете первый элемент после сегодняшнего дня, но не обязательно первый после сегодняшнего дня. –

+0

@ Даниэль: Да, ясно. Но пример в вопросе показывает, что его список уже отсортирован, поэтому я действительно отвечал на это. Он упомянул, что он все равно сортирует, поэтому он, очевидно, знает об этом. Тем не менее я добавлю еще одно предостережение. – Noldorin

+0

Вы сделали ту же ошибку, что и я, - пропустили последние строки вопроса. Он ищет способ получить следующий элемент, но сначала не сортирует список, потому что он, похоже, не доверяет алгоритму сортировки. –

1

Вы могли бы это сделать.

Turn turn = turns 
    .Where(t => t.StartDate >= toDay) 
    .OrderBy(t => t.StartDate) 
    .FirstOrDefault(); 

В случае, когда звонок не является обязательным, его целью является уменьшение количества предметов, которые необходимо заказать.

+0

Если вы удалите В случае вызова, то это не работает на самом деле. Я думаю, вы имеете в виду, что он служит двум целям - или, по крайней мере, более эффективно размещать его перед вызовом OrderBy, а не после. – Noldorin

+0

Упс, хорошая точка. –

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