分组连续日期
本文关键字:日期 连续 | 更新日期: 2023-09-27 18:03:50
我有一个List<DateTime> dates;
我有一个类,它有:
class NonWorkingDay
{
public DateTime Start;
public int Days;
}
我正在想办法把它们整齐地分组。
public List<NonWorkingDay> GetContiguousDates(List<DateTime> dates)
{
}
注意:如果星期五是自然灾害日,而下一个星期一是自然灾害日,则应将它们分组。周末不考虑
例如,如果我有
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<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> source
, Func<T, T, bool> predicate)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
yield break;
List<T> currentGroup = new List<T>() { iterator.Current };
while (iterator.MoveNext())
{
if (predicate(currentGroup.Last(), iterator.Current))
currentGroup.Add(iterator.Current);
else
{
yield return currentGroup;
currentGroup = new List<T>() { 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<DateTime>
变成NonWorkingDay
。其中开始日期是第一个日期,Days
是序列的计数。虽然通常使用First
和Count
都会迭代源序列两次,但我们碰巧知道GroupWhile
返回的序列实际上是一个List
,所以迭代多次不是问题,并且获得Count
甚至是O(1)。
public IEnumerable<NonWorkingDay> GetContiguousDates(IEnumerable<DateTime> dates)
{
return dates.OrderBy(d => d)
.GroupWhile((previous, next) => GetNextWorkDay(previous).Date == next.Date)
.Select(group => new NonWorkingDay
{
Start = group.First(),
Days = group.Count(),
});
}