如何基于两个时间范围列表的交集创建时间范围列表
本文关键字:时间 列表 范围 创建 两个 何基于 | 更新日期: 2023-09-27 18:33:34
我有一个问题需要C#解决方案,这个问题变得太复杂了,无法找到一个简单的解决方案。
我有两个时间范围列表,每个范围都有一个值:列表 A;列表 B.他们之间没有关系。
我想基于 ListB创建第三个列表 (ListC),对于 ListB 中的每个开始和结束对,如果范围在 ListA 中的任何时间范围内都不存在,请在 ListC 中创建两个或多个条目,以便新条目被 ListA 中的条目覆盖。(对不起,很难解释,不要太啰嗦)
一个简单的示例,其中包含一种重叠。两个列表之间可能存在各种重叠。
List<Tuple<int, DateTime, DateTime>> listA = new List<Tuple<int, DateTime, DateTime>>();
listA.Add(new Tuple<int, DateTime, DateTime>(22,DateTime.Parse("09/01/2013 11:00"),DateTime.Parse("09/01/2013 12:00")));
listA.Add(new Tuple<int, DateTime, DateTime>(66, DateTime.Parse("09/01/2013 12:01"), DateTime.Parse("09/01/2013 14:00")));
List<Tuple<int, DateTime, DateTime>> listB = new List<Tuple<int, DateTime, DateTime>>();
listB.Add(new Tuple<int, DateTime, DateTime>(33, DateTime.Parse("09/01/2013 11:30"), DateTime.Parse("09/01/2013 13:30")));
//Desired List
List<Tuple<int, DateTime, DateTime>> listC = new List<Tuple<int, DateTime, DateTime>>();
//listC should contain 2 tuples: first tuple contains the segment from ListB which falls in the first ListA tuple: Tuple(33, "09/01/2013 11:30","09/01/2013 12:00")
//second tuple contains the segment which falls in second ListA tuple: Tuple(33, "09/01/2013 12:01","09/01/2013 13:30")
这是我
的尝试。解决方案非常简单,也许我误解了任务。如果需要在注释中指定的行中使用 <=,>= 而不是 <,>,则可能需要 cosider:
List<Tuple<int, DateTime, DateTime>> listA = new List<Tuple<int, DateTime, DateTime>>();
listA.Add(new Tuple<int, DateTime, DateTime>(22, DateTime.Parse("09/01/2013 11:00"), DateTime.Parse("09/01/2013 12:00")));
listA.Add(new Tuple<int, DateTime, DateTime>(66, DateTime.Parse("09/01/2013 12:01"), DateTime.Parse("09/01/2013 14:00")));
List<Tuple<int, DateTime, DateTime>> listB = new List<Tuple<int, DateTime, DateTime>>();
listB.Add(new Tuple<int, DateTime, DateTime>(33, DateTime.Parse("09/01/2013 11:30"), DateTime.Parse("09/01/2013 13:30")));
List<Tuple<int, DateTime, DateTime>> listC = new List<Tuple<int, DateTime, DateTime>>();
foreach (var rangeB in listB)
{
//a range in A overlaps with a range B
//if any end of the range in A is inside the range in B
//consider using <= and/or >= in these two lines if needed
var overlapping = listA.Where(rangeA => rangeB.Item2 < rangeA.Item2 && rangeA.Item2 < rangeB.Item3 ||
rangeB.Item2 < rangeA.Item3 && rangeA.Item3 < rangeB.Item3).ToList();
overlapping = overlapping.Select(rangeA =>
new Tuple<int, DateTime, DateTime> (rangeB.Item1,
//If a date of A is outside of B
//this will make it equal to the corresponding date of B
(rangeA.Item2 < rangeB.Item2) ? rangeB.Item2 : rangeA.Item2,
(rangeB.Item3 < rangeA.Item3) ? rangeB.Item3 : rangeA.Item3)).ToList();
listC.AddRange(overlapping);
}
如果您按照这些行使用类来保存数据,这将对您有很大帮助。
public class Range
{
public int Id {get; set:}
public DateTime Start {get; set:}
public DateTime End {get; set:}
}
这样可以更轻松地将列表 B 中的每个值与列表 A 中的每个"开始"和"结束"值进行比较,以查看是否存在任何重叠(其中只有 4 种可能的类型)
Type 1: B.Start < A.Start && B.End > A.End (where B totally contains A)
Type 2: B.Start >= A.Start && B.End <= A.End (where A totally contains B)
Type 3: B.Start >= A.Start && B.Start <= A.End (where B overlaps to the right)
Type 4: B.End >= A.Start && B.End <= A.End (where B overlaps to the left)
伪代码类似于
Loop through all entries in List B
{
Loop through all entries in A looking for overlaps
{
If there is an overlap
{
Create a new range from the
appropriate Start and End values
from A or B as required.
Use the ID from B
Add new Range(s) as required
}
}
}
可以使用适用于 .NET 的时间段库来计算交集:
// ----------------------------------------------------------------------
public void PeriodIntersection()
{
// time periods
ITimePeriodCollection periods = new TimePeriodCollection();
periods.Add( new TimeRange( new DateTime( 2013, 9, 1, 11, 0, 0 ), new DateTime( 2013, 9, 1, 12, 0, 0 ) ) );
periods.Add( new TimeRange( new DateTime( 2013, 9, 1, 12, 1, 0 ), new DateTime( 2013, 9, 1, 14, 0, 0 ) ) );
// search range
TimeRange searchRange = new TimeRange( new DateTime( 2013, 9, 1, 11, 30, 0 ), new DateTime( 2013, 9, 1, 13, 30, 0 ) );
// intersections
foreach ( TimeRange period in periods )
{
if ( period.IntersectsWith( searchRange ) )
{
Console.WriteLine( "Intersection: " + period.GetIntersection( searchRange ) );
}
}
// > Intersection: 01.09.2013 11.30:00 - 12:00:00 | 0.00:30
// > Intersection: 01.09.2013 12.01:00 - 13:30:00 | 0.01:29
} // PeriodIntersection