对象的重叠列表
本文关键字:列表 重叠 对象 | 更新日期: 2023-09-27 18:14:36
我有以下
var list = new List<Schedule>();
Schedule
对象具有以下属性:
- 开始时间(日期时间(
- 结束时间(日期时间(
是否有一行代码可以检查list
中的时间约束是否重叠,同时遍历其所有Schedule
成员?
提前谢谢。
我正试图在一个名为
EnforceOverlapPolicy()
的方法中实现上述逻辑,如果有任何冲突,该方法从技术上讲会抛出一个新的异常。
如果你关心的只是是否存在重叠,而不是哪些时间表重叠,那么你应该能够在O(n log n(中做到这一点。关键是按照它们的StartTime
和EndTime
(O(n-logn(部分(对时间表进行排序。然后,您可以枚举结果,并将每个计划的StartTime
与上一个计划的EndTime
进行比较。如果StartTime
早于EndTime
,则您有重叠的时间表。然而,如果没有第三方的帮助,我不认为这可以在一个查询中完成。我自己也是Ix-Main
的粉丝。以下解决方案使用Ix-Main
中的Buffer
函数:
bool hasOverlap =
list
.OrderBy(x => x.StartTime)
.ThenBy(x => x.EndTime)
.Buffer(2, 1)
.Where(x => x.Count == 2)
.Where(x => x[1].StartTime < x[0].EndTime)
.Any();
如果你不想使用第三方库,那么你可以对以下内容做同样的事情:
Schedule first = null;
bool hasOverlap = false;
using(var enumerator = list.OrderBy(x => x.StartTime).ThenBy(x => x.EndTime).GetEnumerator())
{
enumerator.MoveNext();
first = enumerator.Current;
while(enumerator.MoveNext())
{
if(enumerator.Current.StartTime < first.EndTime)
{
hasOverlap = true;
break;
}
}
}
假设性能不是问题(否则考虑重叠的算法(:
var pairs = from f in list
from s in list
where (f.EndTime < s.StartTime) && (f.StartTime < s.EndTime) && (f != s)
select new {First = f, Second = s };
基本上,我们正在检查所有可能的配对是否重叠。
或者,不使用查询语法:
var overlaps = list.SelectMany(l => list, (f, s) => new {f,s})
.Where(x => (x.f.EndTime < x.s.StartTime) &&
(x.f.StartTime < x.s.EndTime) && (x.f != x.s));
这是一种不同的方法,我不确定整件事的性能,但我们的想法是在BitArray中压平由您的时间表定义的范围,该BitArray会发出信号,表明前一个时间表是否已经使用了特定的分钟。
从技术上讲,它也不是一个"一行"的答案,尽管从调用代码的角度来看,它只是一行
所以假设已经定义了一个类ScheduleList
public class ScheduleList : List<Schedule>
{
private BitArray ba = new BitArray(1440);
// Define own Add method to Add a Schedule to the list
// Or override the predefined one....
public Schedule Add(int sh, int sm, int eh, int em)
{
Schedule s = new Schedule();
s.StartTime = new DateTime(1, 1, 1, sh, sm, 0);
s.EndTime = new DateTime(1, 1, 1, eh, em, 0);
// Of course, having full control on the Add phase, you
// could easily enforce your policy at this point.
// You could not accept a new schedule if the time slot is busy
// but we could ignore it at this point
this.Add(s);
return s;
}
public bool IsTimeSlotBusy(Schedule s)
{
int sidx = Convert.ToInt32(TimeSpan.FromMinutes((s.StartTime.Hour * 60) + s.StartTime.Minute).TotalMinutes);
int eidx = Convert.ToInt32(TimeSpan.FromMinutes((s.EndTime.Hour * 60) + s.EndTime.Minute).TotalMinutes);
for (int x = sidx; x <= eidx; x++)
{
if (ba.Get(x)) return true;
ba.Set(x, true);
}
return false;
}
}
现在你可以写这样的
ScheduleList schedules = new ScheduleList();
schedules.Add(12, 0, 12, 30);
schedules.Add(15, 10, 15, 30);
schedules.Add(12, 0, 23, 59);
schedules.Add(14, 0, 23, 59);
// The fake 'one liner'
bool overlap = schedules.Any(s => schedules.IsTimeSlotBusy(s));
Console.WriteLine(overlap);
等着数学家们告诉我为什么这是最糟糕的。(并非讽刺,我真的想知道从数学角度来看这是否糟糕(
public static bool DoesNotOverlap(List<Schedule> timeSlots)
{
DateTime endPrior = DateTime.MinValue;
foreach (Schedule timeSlot in timeSlots.OrderBy(x => x.StartTime))
{
if (timeSlot.StartTime > timeSlot.EndTime || timeSlot.StartTime < endPrior)
return false;
endPrior = timeSlot.End;
}
return true;
}
对于任何需要这一点的人来说,这不是问题所要求的一句话,而是一种简单的方法,可以解决检查具有开始日期和结束日期的重叠DateTime元素的问题
- 使用
OrderBy Linq
运算符对列表进行排序 - 不允许开始的
DateTime
大于结束的DateTime
- 跟踪上一次会议的结束情况,查看是否在调度的CCD_ 18的下一次开始