获取重叠时间段的持续时间

3

我有一个TimeSpan列表,想要获得所有重叠TimeSpan的持续时间。(见图像)

enter image description here

在这种情况下,持续时间必须是2.5小时而不是3小时。有人有想法吗?

例子:

enter image description here

"Administratief"是一个40分钟的预约。"Tafel dekken"是一个30分钟的预约,但它与"Administratief"重叠,所以持续时间为40分钟+10分钟的"Tafel dekken"。还有一个30分钟的"Prolongeren",所以在这种情况下,持续时间必须为80分钟。


所以在您的例子中,结果将是30分钟吗?如果有第三个时间段从9:45到10:30,结果将是什么? - Steve
是的,我知道。它们实际上是预约(DevExpress),因此它们具有StartTime和EndTime。 StartTime和EndTime的持续时间是TimeSpan对象。 - Abusive Vids
@Steve 结果仍然是2.5小时。 - Abusive Vids
我有一个类库,非常适合这种情况:https://intervals.codeplex.com/ - 你可以将所有的约会构建为"Interval<DateTime>"的形式,把它们放入集合中并对该集合运行".Slice()"方法。这样你就能得到不重叠的时间片段,它们的总和是2.5个小时。每个时间片段还将链接回组成它的Interval。在你的情况下,你将得到从8:30到9:15的一个时间片段,从9:15到9:30的一个时间片段,从9:30到10:00的一个时间片段,从10:00到10:15的一个时间片段以及从10:15到11:00的一个时间片段。 - Lasse V. Karlsen
@LasseV.Karlsen 我会尝试一下的 ;). 谢谢。 - Abusive Vids
如果你只关心总时间而不是实际的不同重叠“片段”,那么ChrisF的答案要简单得多。如果以后需要更高级的处理,你可以随时回头看我的类库。 - Lasse V. Karlsen
2个回答

3
假设您已经有了开始时间和持续时间,您可以通过获取最小的开始时间和最大的结束时间,然后计算差异来完成此操作:
DateTime minStart = timeList.Min(l => l.StartTime);
DateTime maxEnd = timeList.Max(l => l.EndTime);

TimeSpan duration = maxEnd - minStart;

如果没有直接给出结束时间,则需要从开始时间和持续时间计算得到 EndTime 属性:
public DateTime EndTime
{
    get { return this.StartTime.Add(this.Duration); }
}

这将获取约会的总持续时间,并不考虑约会之间有时间间隔的情况。您需要先将列表处理成子列表,其中约会重叠或是连续的。可以使用以下伪代码:

var orderedAppointments = appointments.OrderBy(a => a.StartTime);
foreach (var appointment in orderedAppointments)
{
    if (first appointment)
        add to new sub list and add sub list to list of lists
    else if (appointment.StartTime <= subList.Max(s => s.EndTime))
        add to existing sub list
    else
        add to new sub list and add sub list to list of lists
}

然后,您可以使用初始代码获取每个子列表的总持续时间。

他说:“可能会有预约之间的空隙,也可能没有,这就是重叠区间。” - Lasse V. Karlsen
@AbusiveVids - 我已经添加了你需要获取连续/重叠约会组的算法。 - ChrisF
@ChrisF 谢谢,我会去看看。我认为这一定是解决方案。 - Abusive Vids

3

一个简单但效率低下的算法(O(n²)),不需要排序列表。
首先,所有重叠的区间被合并,然后区间长度被加总(向下滚动):

struct TimeRange
{
    DateTime Start;
    DateTime End;

    public TimeRange(DateTime start, DateTime end)
    {
        Start = start;
        End = end;
    }

    public TimeSpan Duration
    {
        get
        {
            return End-Start;
        }
    }

    public static bool Overlap(TimeRange tr1, TimeRange tr2)
    {
        return (tr2.Start <= tr1.End && tr1.Start <= tr2.End);
    }

    public static TimeRange Merge(TimeRange tr1, TimeRange tr2)
    {
        return new TimeSpan(
            (tr1.Start < tr2.Start) ? tr1.Start : tr2.Start,
            (tr1.End > tr2.End) ? tr1.End : tr2.End
        );
    }
}



List<TimeRange> timeRanges; // A *copy* of your data list

for(int i = 0; i < timeRanges.Count; i++)
{
    for(int j = i+1; j < timeRanges.Count; j++)
    {
        if(TimeRange.Overlap(timeRanges[i],timeRanges[j])
        {
            timeRanges[i] = TimeRange.Merge(timeRanges[i],timeRanges[j]);
            timeRanges.RemoveAt(j);
            j--;
        }
    }
}

TimeSpan totalDuration = TimeSpan.Zero;
foreach(TimeRange in timeRanges)
{
    totalDuration += timeRanges.Duration;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接