计算多个日期/时间范围之间的位置和交集数量?

5
我需要计算多个日期范围之间的交集位置和重叠交集数。然后我需要显示哪些日期/时间范围与这些交叉部分重叠。稍微有点复杂,所以我会尽力通过提供一个示例来解释。我正在使用VB.Net工作,但C#示例也可以接受,因为我两种语言都用。

我们有几个涉及同一系统的高风险任务。下面我有三个示例作业,命名为HR1/2/3/4,具有开始和结束日期/时间。

  • HR1 {1/6/2010 10:00 - 1/6/2010 15:00}
  • HR2 {1/6/2010 11:00 - 1/6/2010 18:00}
  • HR3 {1/6/2010 12:00 - 1/6/2010 14:00}
  • HR4 {1/6/2010 18:00 - 1/6/2010 20:00}

我想要的最终结果如下所示。我很难以任何方式描述它,除了通过示例。

  • HRE1 {2010年1月6日10:00 - 2010年1月6日11:00} - 交集1
  • {第1个时间段的结束时间,仅为易读性,解决方案中不需要}
  • HRE1 {2010年1月6日11:00 - 2010年1月6日12:00} - 交集2
  • HRE2 {2010年1月6日11:00 - 2010年1月6日12:00} - 交集2
  • {第2个时间段的结束时间,仅为易读性,解决方案中不需要}
  • HRE1 {2010年1月6日12:00 - 2010年1月6日14:00} - 交集3
  • HRE2 {2010年1月6日12:00 - 2010年1月6日14:00} - 交集3
  • HRE3 {2010年1月6日12:00 - 2010年1月6日14:00} - 交集3
  • {第3个时间段的结束时间,仅为易读性,解决方案中不需要}
  • HRE1 {2010年1月6日14:00 - 2010年1月6日15:00} - 交集2
  • HRE2 {2010年1月6日14:00 - 2010年1月6日15:00} - 交集2
  • {第4个时间段的结束时间,仅为易读性,解决方案中不需要}
  • HRE2 {2010年1月6日15:00 - 2010年1月6日18:00} - 交集1
  • {第5个时间段的结束时间,仅为易读性,解决方案中不需要}
  • HR4 {2010年1月6日18:00 - 2010年1月6日20:00} - 交集1

非常感谢您的帮助。


1
你能解决两个时间间隔的问题吗? - Eric Lippert
1个回答

5
var timePoints = (from r in ranges select r.Start)
    .Concat(from r in ranges select r.End)
    .Distinct().OrderBy(dt => dt).ToArray();

var intersections = from i in Enumerable.Range(0, timePoints.Length - 1)
                    let start = timePoints[i]
                    let end = timePoints[i + 1]
                    from range in ranges
                    where range.Start <= start && range.End >= end
                    select new { Range = range, Start = start, End = end };

编辑: 修改了计算交点的代码:

var timePoints = (from r in ranges select r.Start)
    .Concat(from r in ranges select r.End)
    .Distinct().OrderBy(dt => dt).ToArray();

var intersectionGroups = from i in Enumerable.Range(0, timePoints.Length - 1)
                         let start = timePoints[i]
                         let end = timePoints[i + 1]
                         select new
                         {
                             Start = start,
                             End = end,
                             Ranges =
                                 from range in ranges
                                 where range.Start <= start && range.End >= end
                                 select range
                         };

var intersections = from intGroup in intersectionGroups
                    let count = intGroup.Ranges.Count()
                    from range in intGroup.Ranges
                    select new
                    {
                        Range = range,
                        Start = intGroup.Start,
                        End = intGroup.End,
                        Count = count
                    };

我不知道您想用结果做什么,但使用intersectionGroups而不是intersections可能会更好。


哇!这非常接近我要找的东西。起初我不明白,但在VS中运行了一遍后,一分钟后就有了意识。脑海中浮现出两个小问题,其中一个是我的错,因为我没有在原始帖子中提到。首先,它没有告诉我有多少其他范围与之重叠。因此,对于11:00到12:00时间范围,值将为2。也许可以添加一个名为OverlapCount的附加属性或类似的内容。其次:这是我没有提到的情况。数组中没有与任何内容重叠的项目会被删除。我们有办法保留它们吗?我已经将此添加到帖子中。 - Peter
我的代码没有删除与任何内容不重叠的范围(例如您示例中的HR4)。我会查看计数。 - svick
svick,我的朋友,这真是一件美妙的事情。实际上,在发布之前我已经开发出了解决方案,但它太可怕了,我知道必须有一个简单的解决方案。再次感谢您的帮助,linq再次拯救了这一天。 - Peter

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