分组连续日期
我有一个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
是序列的计数。 虽然通常同时使用First
和Count
会迭代源序列两次,但我们碰巧知道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(), }); }