How to get the next active item in a list with LINQ
I have a little problem where I want to find the next "active" item in a list with linq. Then the next "active" element is defined by startDate and EndDate. Here is a list of examples.
//-- 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>();
Is there a good solution to find the next turn using the startDate / endDate properties on Turn. I tried to first order the list by startdate and find First in the list, but I realized there was a "safer" way to get it so that it doesn't need the list in the correct order to find the correct Turn.
source to share
Why don't you just get the first item with a start date after today? I added an explict call OrderBy()
to make sure the list is sorted. If you know it's sorted, you can leave that, of course.
turns.OrderBy(t => t.StartDate).FirstOrDefault(t => t.StartDate > today);
UPDATE
I missed the last lines. Yes, you can do this without explicitly sorting the list. You should search the list for an element with a start date after today, and ther should not be an element with a start date after today, but before the current position. But this will really slow down the search, because you have to loop through the entire list for each element doing the O (n²) thing.
turns.Single(t =>
t.StartDate > today &&
turns.All(u => u.StartDate <= today || u.StartDate > t.StartDate))
This assumes the turns do not overlap. If they overlap, you must use First
instead Single
or add additional constraints to get a unique result. Finally, use a sorting solution - this solution is by no means safer than sorting and getting the first item.
source to share
I guess you just want:
var turn = turns.SkipWhile(t => t.EndDate < today).FirstOrDefault();
This will return the first move that contains or after the specified date today
, which is what you seem to be looking for. It also assumes that your list is turns
already sorted, of course.
Edit: Looks like I missed the bit about not wanting to sort the list. I'm still not entirely sure if you need to choose the appropriate rotation that will allow me to improve the query.
source to share