C# 分组连续日期
我有一个C# 分组连续日期,c#,asp.net,linq-to-sql,C#,Asp.net,Linq To Sql,我有一个列表日期 我有一个课程: class NonWorkingDay { public DateTime Start; public int Days; } 我正试图找出一个干净的方法来将他们分组 public List<NonWorkingDay> GetContiguousDates(List<DateTime> dates) { } 产出将是: Start = September 3 2013, Days = 1 Start = Septemb
列表日期代码>
我有一个课程:
class NonWorkingDay
{
public DateTime Start;
public int Days;
}
我正试图找出一个干净的方法来将他们分组
public List<NonWorkingDay> GetContiguousDates(List<DateTime> dates)
{
}
产出将是:
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;
}
}
现在,让我们把这一切放在一起。首先我们点了几天。(如果您确保它们总是按顺序出现,您可以删除该部分。)然后我们将连续的项目分组,而每个项目都是前一个项目的下一个工作日
然后,我们需要做的就是将连续日期的IEnumerable
转换为非工作日
。因此,开始日期是第一个日期,Days
是序列的计数。虽然通常使用First
和Count
会对源序列进行两次迭代,但我们碰巧知道GroupWhile
返回的序列实际上是一个隐藏的列表,因此多次迭代并不成问题,而获得Count
甚至是O(1)
public IEnumerable GetContinguousDates(IEnumerable日期)
{
返回日期。订购人(d=>d)
.GroupWhile((上一个,下一个)=>GetNextWorkDay(上一个).Date==下一个.Date)
.选择(组=>新的非工作日
{
Start=group.First(),
天数=组。计数(),
});
}
您能否每周分组,然后清点组中的项目?按周分组可以在这里找到不,因为可能有2.5周的星期一到星期五在Thereahhh gotcha,所以你希望看到12.5,而不是5,5,2.5这有帮助吗@有些可能不会立即显现,但在这种情况下,它实际上只是复制/粘贴。。。
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;
}
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(),
});
}