如何根据两个时间范围列表中的交叉点创建时间范围列表?

时间:2013-10-01 03:09:21

标签: c#

我遇到需要c#解决方案的问题,这个问题对于一个简单的解决方案来说太复杂了。

我有两个时间范围列表加上每个范围的值:ListA;数组listB。他们之间没有任何关系。

我想基于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")

3 个答案:

答案 0 :(得分:1)

这是我的尝试。解决方案非常简单,也许我误解了任务。 如果您需要使用&lt; =,&gt; =而不是&lt;,&gt;,您可能需要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);
        }

答案 1 :(得分:0)

如果您沿着这些行使用类来保存数据,那将会对您有很大帮助。

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
        }
    }
}

答案 2 :(得分:0)

您可以使用Time Period Library for .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