我有一个字典,按周提供工作时间间隔,如MsProject提供的:
字典具有以下类型:
new Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>>
{
[DayOfWeek.Monday] = new[]
{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
},
[DayOfWeek.Tuesday] = new[]
{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
},
...
我的目标是实现一个迭代器,产生日期时间间隔,从作为参数传递的datetime开始:
IEnumerable<Tuple<DateTime, TimeSpan>> IterateTimeslots(DateTime startingFrom);
测试用例#1 :
字典中包含工作小时(晚上8点至12点),(下午1点至下午5点)的星期几和星期六,执行
IterateTimeslots(DateTime.Parse(&#34; 03/20/2016 12:00 AM&#34;))// Sunday
应该返回:
(03/21/2016 8AM, 4hrs)
(03/21/2016 1PM, 4hrs)
(03/22/2016 8AM, 4Hrs)
(03/22/2016 8AM, 4Hrs)
... (endless iteration)
测试用例#2(合并相邻区间): 字典可以表示第二天的间隔,如下所示:
[Monday] = (12AM-9AM),(9PM-12AM) //Ending 12AM = TimeSpan.FromHours(24)
[Tuesday] = (12AM-9AM),(9PM-12AM)
...
迭代器应将相邻间隔合并为一个。所以对于startDate&#34; 03/20/2016 12 AM&#34;它将返回以下内容:
(03/21/2016 12AM, 9Hrs)
(03/21/2016 9PM, 12Hrs) //Intervals crosses to next day
(03/22/2016 9PM, 12Hrs) //Intervals crosses to next day
(03/23/2016 9PM, 12Hrs) //Intervals crosses to next day
... (endless enumeration)
测试用例#3(24/7): 24/7工作时间应使用TimeSpan = TimeSpan.MaxValue迭代单个时间间隔。所以字典将包含每周的每一天smth,如下所示:
[Sunday] = (12AM-12AM)
[Monday] = (12AM-12AM)
[Tuesday] = (12AM-12AM)
...
所以对于startDate&#34; 03/20/2016 8AM &#34;它应该只用一个项目返回枚举:
(03/20/2016 8AM, TimeSpan.MaxValue)
如何实施 IterateTimeslots 功能?任何帮助都是适用的
答案 0 :(得分:0)
我对此进行了实验并提出了以下建议。抱歉,超过一半的代码是测试数据,但我添加了它,以便整个程序可以快速运行。另外,我还没有构建问题中准确提到的代码。在给定IEnumerable<Tuple<DateTime, TimeSpan>>
作为输入的情况下,代码主要侧重于生成Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>>
。
public class Program
{
public static void Main(string[] args)
{
Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>> workHours = new Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>>
{
{
DayOfWeek.Sunday,
new[] {
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
},
{
DayOfWeek.Monday,
new[] {
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
},
{
DayOfWeek.Tuesday,
new[]{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
}
,
{
DayOfWeek.Wednesday,
new[]{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
}
,
{
DayOfWeek.Thursday,
new[]{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
}
,
{
DayOfWeek.Friday,
new[]{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
}
,
{
DayOfWeek.Saturday,
new[]{
Tuple.Create(TimeSpan.FromHours(8), TimeSpan.FromHours(12)), //8AM-12PM
Tuple.Create(TimeSpan.FromHours(13), TimeSpan.FromHours(17)) //1PM-5PM
}
}
};
Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>> workHours1 = new Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>>
{
{
DayOfWeek.Sunday,
new[] {
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
},
{
DayOfWeek.Monday,
new[] {
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
},
{
DayOfWeek.Tuesday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
}
,
{
DayOfWeek.Wednesday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
}
,
{
DayOfWeek.Thursday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
}
,
{
DayOfWeek.Friday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
}
,
{
DayOfWeek.Saturday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(9)), //12AM-9AM
Tuple.Create(TimeSpan.FromHours(21), TimeSpan.FromHours(24)) //9PM-12AM
}
}
};
Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>> workHours2 = new Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>>
{
{
DayOfWeek.Sunday,
new[] {
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
},
{
DayOfWeek.Monday,
new[] {
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
},
{
DayOfWeek.Tuesday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
}
,
{
DayOfWeek.Wednesday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
}
,
{
DayOfWeek.Thursday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
}
,
{
DayOfWeek.Friday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
}
,
{
DayOfWeek.Saturday,
new[]{
Tuple.Create(TimeSpan.FromHours(0), TimeSpan.FromHours(24)) //12AM-12AM
}
}
};
DateTime currDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
DateTime firstDateOfWeek = currDate.AddDays(-1 * (int)currDate.DayOfWeek);
Console.WriteLine("First Date Of Week " + firstDateOfWeek);
//this list will produce values of test case #1
List<Tuple<DateTime, TimeSpan>> dailyWorkHours = workHours.SelectMany(kvp => kvp.Value,
(k, v) => Tuple.Create<DateTime, TimeSpan> (
firstDateOfWeek.AddDays((int)k.Key).AddHours(v.Item1.Hours),
v.Item2 - v.Item1
)).ToList();
foreach (var item in dailyWorkHours)
{
Console.WriteLine(item.Item1 + " " + item.Item2);
}
//handle Test case #2
//Test case #3 is extension of test case #2
List<Tuple<DateTime, TimeSpan>> finalWorkHours = new List<Tuple<DateTime, TimeSpan>>();
finalWorkHours.Add(dailyWorkHours.First());
//idea is to compare current item in dailyWorkHours
//with the previous item (that is currently in finalWorkHours)
foreach (var item in dailyWorkHours)
{
if (dailyWorkHours.IndexOf(item) == 0)
{
continue;
}
Tuple<DateTime, TimeSpan> finalLast = finalWorkHours.Last();
//handle Test case #2 merge last item in finalWorkHours with current item
//if last item's time span added to last item's date and it equals to current item date
if (DateTime.Compare(finalLast.Item1.AddHours(finalLast.Item2.TotalHours), item.Item1) == 0)
{
finalWorkHours.RemoveAt(finalWorkHours.Count - 1);
finalWorkHours.Add(Tuple.Create(finalLast.Item1, finalLast.Item2.Add(item.Item2)));
}
else {
finalWorkHours.Add(item);
}
}
Console.WriteLine("Final work hours");
foreach (var item in finalWorkHours)
{
Console.WriteLine(item.Item1 + " " + item.Item2.TotalHours + " hrs");
}
Console.ReadKey();
}
}
答案 1 :(得分:0)
在这里(参见代码中的注释):
public static class Algorithms
{
public static IEnumerable<Tuple<DateTime, TimeSpan>> IterateTimeslots(
this Dictionary<DayOfWeek, IEnumerable<Tuple<TimeSpan, TimeSpan>>> input,
DateTime startingFrom)
{
// Convert the input to ordered array of ranges containing
// absolute offsets from the beginning of the week
var ranges = input.SelectMany(e => e.Value.Select(v => new
{
Start = TimeSpan.FromDays((int)e.Key) + v.Item1,
End = TimeSpan.FromDays((int)e.Key) + v.Item2
}))
.OrderBy(e => e.Start)
.ToArray();
// Corner case: empty input
if (ranges.Length == 0) yield break;
// Test case #2: merge adjacent ranges
int first = 0, last = first;
for (int i = 1; i < ranges.Length; i++)
{
if (ranges[i].Start > ranges[last].End)
ranges[++last] = ranges[i];
else
ranges[last] = new { Start = ranges[last].Start, End = ranges[i].End };
}
var weekLength = TimeSpan.FromDays(7);
if (ranges[last].End == weekLength && ranges[first].Start == TimeSpan.Zero)
{
// Test case #3: (24/7)
if (last == first)
{
yield return Tuple.Create(startingFrom, TimeSpan.MaxValue);
yield break;
}
ranges[last] = new { Start = ranges[last].Start, End = ranges[last].End + ranges[first].End };
first++;
}
// Test case #1: Generate infinite intervals
var weekStart = new DateTime(startingFrom.Year, startingFrom.Month, startingFrom.Day,
0, 0, 0, startingFrom.Kind) - TimeSpan.FromDays((int)startingFrom.DayOfWeek);
for (int i = 0; ; i++)
{
if (i > last)
{
weekStart += weekLength;
i = first;
}
var start = weekStart + ranges[i].Start;
var end = weekStart + ranges[i].End;
if (end > startingFrom)
{
if (start < startingFrom) start = startingFrom;
yield return Tuple.Create(start, end - start);
}
}
}
}