我必须实现类似于Outlook Meeting Organizer的调度算法,其中我有几个人参加会议,组织者找到所有来自邀请者的人都可用的时间段。所以,让我们说我有第三方服务实现以下界面:
B third = new B(12);
DateTimeInterval是:
interface IAvailabilityProvider
{
IEnumerable<DateTimeInterval> GetPersonAvailableTimeSlots(
string personName, DateTime startFrom);
}
GetPersonAvailableTimeSlots返回无限迭代器,它将枚举人工作时间的所有时间段,不包括周末和假日等等,对未来无限。
我的任务是实现一个函数,该函数接受一组迭代器并返回交叉点的另一个迭代器:
class DateTimeInterval{
public DateTime Start {get;set;}
public TimeSpan Length {get;set;}
}
当所有人都可用时,它获取所有人的可用时隙的迭代器并返回相交的时隙。在内部我必须实现以下功能:
IEnumerable<DateTimeInterval> GetIntersections(
string[] persons, DateTime startFrom);
答案 0 :(得分:2)
对我来说,解决方案似乎非常简单。
static IEnumerable<DateTimeInterval> GetIntersections(IEnumerable<DateTimeInterval>[] personsAvailableSlots)
{
var enumerators = personsAvailableSlots.Select(timeline => timeline.GetEnumerator()).ToArray();
// Intersection is empty when at least one of iterators is empty.
for (int i = 0; i < personsAvailableSlots.Length; i++) if (!enumerators[i].MoveNext()) yield break;
while (true)
{
// first we ensure that intersection exists at the current state
// if not so, we have to move some iterators forward
var start = enumerators.Select(tl => tl.Current).Max(interval => interval.Start);
foreach (var iter in enumerators)
while (iter.Current.Start + iter.Current.Length <= start)
if (!iter.MoveNext()) yield break;
// now we check if the interval exists
var int_start = enumerators.Select(tl => tl.Current).Max(interval => interval.Start);
var int_end = enumerators.Select(tl => tl.Current).Min(interval => interval.Start + interval.Length);
if (int_end > int_start)
{
//if so, we return it
yield return new DateTimeInterval()
{
Start = int_start,
Length = int_end - int_start
};
// and, finally, we ensure next interval to start after the current one ends
//
// CAUTION: We are able to move iterators whose current interval have passed only.
// We will miss huge spans which cover several intervals in other iterators otherwise.
//
// In fact we should move the only inerator - that one wich currently limits the last result
foreach (var iter in enumerators)
while (iter.Current.Start + iter.Current.Length == int_end)
if (!iter.MoveNext()) yield break;
}
}
}
我已经针对几个简单的场景对此进行了测试,希望我不会遗漏一些重要的事情。