分组连续日期

我有一个List dates;

我有一个class级:

 class NonWorkingDay { public DateTime Start; public int Days; } 

我试图想出一种干净的方式来分组它们。

 public List GetContiguousDates(List dates) { } 

注意:如果星期五有一个NWD,而下一个是星期一,则应对它们进行分组。 周末不被考虑。

例如,如果我有

 September 3 2013 September 20 2013 September 23 2013 September 24 2013 September 30 2013 October 1 2013 

输出将是:

 Start = September 3 2013, Days = 1 Start = September 20 2013, Days = 3 //weekend got skipped Start = September 30 2013, Days = 2 

有没有办法做到这一点(没有一堆计数器变量)和使用.Select或.Where等。

谢谢

因此,我们将从这个通用迭代器函数开始。 它接受一个序列和一个谓词,它接受两个项并返回一个布尔值。 它将读取源中的项目,而项目及其前一项目将根据谓词返回true,下一项将位于“下一组”中。 如果返回false,则前一个组已满,并且下一个组已启动。

 public static IEnumerable> GroupWhile(this IEnumerable source , Func predicate) { using (var iterator = source.GetEnumerator()) { if (!iterator.MoveNext()) yield break; List currentGroup = new List() { iterator.Current }; while (iterator.MoveNext()) { if (predicate(currentGroup.Last(), iterator.Current)) currentGroup.Add(iterator.Current); else { yield return currentGroup; currentGroup = new List() { iterator.Current }; } } yield return currentGroup; } } 

我们还需要这个简单的帮助方法,它根据日期获得下一个工作日。 如果你想要整合假期,那么从琐碎到非常困难,但这就是逻辑的发展方向。

 public static DateTime GetNextWorkDay(DateTime date) { DateTime next = date.AddDays(1); if (next.DayOfWeek == DayOfWeek.Saturday) return next.AddDays(2); else if (next.DayOfWeek == DayOfWeek.Sunday) return next.AddDays(1); else return next; } 

现在把它们放在一起。 首先我们订购日子。 (如果确保它们总是按顺序排列,则可以删除该部分。)然后,我们将连续项目分组,同时每个项目是上一个工作日的下一个工作日。

然后我们需要做的就是将连续日期的IEnumerable转换为NonWorkingDay 。 为此,开始日期是第一个日期,而Days是序列的计数。 虽然通常同时使用FirstCount会迭代源序列两次,但我们碰巧知道GroupWhile返回的序列实际上是一个引擎盖下的List ,因此多次迭代它不是问题,并且得到Count甚至是O( 1)。

 public IEnumerable GetContiguousDates(IEnumerable dates) { return dates.OrderBy(d => d) .GroupWhile((previous, next) => GetNextWorkDay(previous).Date == next.Date) .Select(group => new NonWorkingDay { Start = group.First(), Days = group.Count(), }); }