我正在尝试确定时间范围是否在CRUD页面上重叠但是卡住了。
我可以使用下面的代码使用两个时间范围,但我需要它也适用于3。
public static bool IsOverLapping(ConfigureViewModel viewModel)
{
bool status = false;
var times = viewModel.Periods.OrderBy(x => x.StartTime.TimeOfDay).ToList();
for (var i = 0; i <= times.Count - 2; i++)
{
if (times[i].StartTime.TimeOfDay <= times[i + 1].EndTime.TimeOfDay)
{
if (times[i + 1].StartTime.TimeOfDay >= times[i].EndTime.TimeOfDay)
status = false;
else
return true;
}
else
return true;
}
return status;
}
数据以DateTime值的形式出现,这就是我只查看'TimeOfDay'值的原因。该图显示了CRUD页面的布局。
答案 0 :(得分:1)
这实际上比看起来更棘手,因为你需要处理横跨午夜的时间段。
使用一些扩展方法,您可以直接进行。
首先,确定时间是否介于两个人之间:
public static bool Between(this TimeSpan aTime, TimeSpan startTime, TimeSpan endTime) => (startTime <= endTime) ? (startTime < aTime && aTime < endTime)
: (startTime < aTime || aTime < endTime);
然后使用范围的Period
类创建一个特殊版本:
public static bool Between(this TimeSpan aTime, Period aPeriod) => aTime.Between(aPeriod.StartTime.TimeOfDay, aPeriod.EndTime.TimeOfDay);
最后为一个范围是否与第二个范围重叠创建一个测试(注意这是不对称的):
public static bool Overlaps(this Period aPeriod, Period bPeriod) => aPeriod.StartTime.TimeOfDay.Between(bPeriod) || aPeriod.EndTime.TimeOfDay.Between(bPeriod);
现在浏览所有范围并检查是否有任何范围与另一个范围重叠:
public static bool IsOverLapping(this List<Period> periods) {
var periodCount = periods.Count;
for (int j1 = 0; j1 < periodCount; ++j1)
for (int j2 = 0; j2 < periodCount; ++j2)
if (j1 != j2 && periods[j1].Overlaps(periods[j2]))
return true;
return false;
}
最后,您可以在ConfigureViewModel
方法中使用该方法:
public static bool IsOverLapping(ConfigureViewModel viewModel)
{
bool status = false;
var times = viewModel.Periods.OrderBy(x => x.StartTime.TimeOfDay).ToList();
return times.IsOverLapping();
}
答案 1 :(得分:1)
我认为它可能比听起来更简单。如果你有period1和period2,如果period1.Start&gt;它们不重叠。 period2.End或者如果period1.End&lt; period2.Start。如果这些都不是真的,那么我们知道它们是重叠的:
我在Period
类上创建了一个静态方法:
public class Period
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public static bool AreOverlapping(Period first, Period second)
{
if (first == null || second == null) return false;
// These two conditions define "overlapping" and must be true
return first.StartTime <= second.EndTime &&
first.EndTime >= second.StartTime;
}
}
然后,这应该简化方法中的逻辑,该逻辑检测组中是否存在任何重叠周期:
public static bool DoAnyOverlap(List<Period> periods)
{
if (periods == null || periods.Count < 2) return false;
var ordered = periods.OrderBy(p => p.StartTime).ToList();
for (var i = 0; i < ordered.Count - 1; i++)
{
if (Period.AreOverlapping(ordered[i], ordered[i + 1])) return true;
}
return false;
}
如果由于某种原因您无法修改Period
类,则可以轻松地将逻辑合并到DoAnyOverlap
方法中:
public static bool DoAnyOverlap(List<Period> periods)
{
if (periods == null || periods.Count < 2) return false;
var ordered = periods.Where(p => p != null).OrderBy(p => p.StartTime).ToList();
for (var i = 0; i < ordered.Count - 1; i++)
{
if (ordered[i].StartTime <= ordered[i + 1].EndTime &&
ordered[i].EndTime >= ordered[i + 1].StartTime)
{
return true;
}
}
return false;
}
答案 2 :(得分:1)
试试这个:
var periods = new[]
{
new { start = TimeSpan.Parse("10:00"), end = TimeSpan.Parse("14:00") },
new { start = TimeSpan.Parse("16:00"), end = TimeSpan.Parse("17:00") },
new { start = TimeSpan.Parse("13:00"), end = TimeSpan.Parse("15:00") },
};
bool overlapping =
Enumerable
.Range(0, periods.Length)
.SelectMany(i =>
Enumerable
.Range(i + 1, periods.Length - i - 1),
(i, j) => new { A = periods[i], B = periods[j] })
.Any(x => !(x.B.start >= x.A.end || x.B.end <= x.A.start));
它也适用于DateTime
。
答案 3 :(得分:0)
假设ConfigureViewModel
类看起来像这样:
class ConfigureViewModel
{
...
public List<Period> Periods { get; set; }
}
class Period
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
您可以使用 .NET时间段库
PM&GT; Install-Package TimePeriodLibrary.NET
而且IsOverLapping
mathod可能看起来很简单:
public static bool IsOverLapping(ConfigureViewModel vm, int numberOfOverlaps)
{
var ranges = vm.Periods.Select(q => new TimeRange(q.StartTime, q.EndTime));
TimePeriodCollection periodCollection = new TimePeriodCollection(ranges);
TimePeriodIntersector<TimeRange> intersector = new TimePeriodIntersector<TimeRange>();
return intersector.IntersectPeriods(periodCollection).Count > numberOfOverlaps;
}