3次或更多次重叠C#

时间:2018-04-16 22:09:39

标签: c# datetime

我正在尝试确定时间范围是否在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页面的布局。

enter image description here

4 个答案:

答案 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;
}