简体   繁体   中英

How to get next active item in a list with LINQ

I have a small problem where I want to find the next "active" item in a list with linq. Then next "active" item is defined by a startDate and EndDate. Here is an example list.

    //-- 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 by using startDate/endDate properties on Turn. I have tryed to first order the list by startdate and the find First one in the list, but I wounder if there is a more "safe" way to get it that dosen't need the list in correct order to find the correct Turn.

You could do this.

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

The Where call is optional - its goal is to reduce the amount of items that have to be ordered.

I think you just want:

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

This would return the first turn either containing or after the given date today , which what you seem to be looking for. It also assumes that your turns list is already sorted, of course.

Edit: It appears I missed the bit about you not wanting to sort the list. I'm still not completely sure on the conditions you require to select the appropiate turn, which would enable me to improve the query.

Why don't you just get the first item with a start date after today? I added an explict OrderBy() call just to be sure that the list is sorted. If you know that it is sorted, you can leave that out, of course.

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

UPDATE

I missed your last lines. Yes, you can do it without sorting the list explicitly. You have to search the list for the item with a start date after today and ther must be no item with a start date after today but before that of the current item. But this will really slow down the search because you have to look at the whole list for every item making the thing O(n²).

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

This assumes that the turns are non-overlapping. If they overlapp, you must use First instead of Single or add additional constraints to get a unique result. And finally: use the the sorting solution - this solution is by no means safer than sorting and getting the first item.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM