【问题标题】:How to get next active item in a list with LINQ如何使用 LINQ 获取列表中的下一个活动项
【发布时间】:2009-05-06 10:03:45
【问题描述】:

我有一个小问题,我想用 linq 在列表中找到下一个“活动”项目。然后下一个“活动”项目由 startDate 和 EndDate 定义。这是一个示例列表。

    //-- 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>();

是否有一个很好的解决方案可以通过在 Turn 上使用 startDate/endDate 属性来找到下一个回合。我尝试按 startdate 对列表进行第一次排序,然后在列表中找到第一个,但如果有更“安全”的方法来获取它,我会发现它不需要按正确顺序列出的列表来找到正确的转弯。

【问题讨论】:

  • 我已经提出了一个解决方案,但是请您更具体地说明选择合适转弯的条款吗?

标签: c# .net linq


【解决方案1】:

你可以这样做。

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

Where 调用是可选的 - 它的目标是减少必须订购的商品数量。

【讨论】:

  • 如果您删除 Where 调用,则它实际上不起作用。我认为您的意思是它有两个目的 - 或者至少将它放在 OrderBy 调用之前而不是之后更有效。
【解决方案2】:

为什么不直接获取开始日期在今天之后的第一个项目?我添加了一个明确的OrderBy() 调用,以确保列表已排序。当然,如果您知道它已排序,则可以忽略它。

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

更新

我错过了你的最后几行。是的,您可以在不明确对列表进行排序的情况下执行此操作。您必须在列表中搜索开始日期在今天之后的项目,并且不能有开始日期在今天之后但在当前项目之前的项目。但这确实会减慢搜索速度,因为您必须查看整个列表中的每个项目,使得事情 O(n²)。

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

这假设转弯不重叠。如果它们重叠,您必须使用First 而不是Single 或添加额外的约束以获得唯一的结果。 最后:使用排序解决方案 - 此解决方案绝不比排序和获取第一个项目更安全。

【讨论】:

  • 我尝试了最后一条语句,但速度很慢,我想我需要先对列表进行排序并获取 FirstOrDefault... 看起来这是激活我想要的最简单的方法...
【解决方案3】:

我想你只是想要:

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

这将返回包含或在给定日期today 之后的第一个回合,您似乎正在寻找它。当然,它还假定您的 turns 列表已经排序。

编辑:看来我错过了关于您不想对列表进行排序的一点。我仍然不能完全确定选择合适转弯所需的条件,这将使我能够改进查询。

【讨论】:

  • 如果列表未排序,这可能会失败 - 您只返回今天之后的第一项,但不一定是今天之后的第一项。
  • @Daniel:是的,很明显。但是问题中的示例表明他的列表已经排序,所以我真的对此做出了回应。无论如何,他提到了对其进行分类,因此他显然意识到了这个问题。尽管如此,我还是要补充一点。
  • 你犯了和我一样的错误——错过了问题的最后几行。他正在寻找一种方法来获取下一项,但没有先对列表进行排序,因为他似乎不信任排序算法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-24
相关资源
最近更新 更多