2013-10-01 45 views
2

我有一个需要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") 

回答

1

这是我的尝试。解决方案非常简单,也许我误解了任务。 你可能想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); 
     } 
0

,如果你使用的类沿着这些线路,以保持它会帮助你显著你的数据。

public class Range 
{ 
    public int Id {get; set:} 
    public DateTime Start {get; set:} 
    public DateTime End {get; set:} 
} 

这将使它更容易为你的每个值的每个表A的开始和结束值的比较列表B,看看是否有任何重叠(其中只有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 
     } 
    } 
} 
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