【问题标题】:How to create a list of time ranges based on intersections from two lists of time ranges?如何根据两个时间范围列表的交集创建时间范围列表?
【发布时间】:2013-10-07 02:06:52
【问题描述】:

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

我有两个时间范围列表以及每个范围的值:ListA;清单 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")

【问题讨论】:

    标签: c#


    【解决方案1】:

    这是我的尝试。解决方案非常简单,也许我误解了任务。 如果您需要在 cmets 中指定的行中使用 = 而不是 ,您可能需要考虑:

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

    【讨论】:

      【解决方案2】:

      如果您按照这些思路使用一个类来保存您的数据,将会对您有很大帮助。

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

      这将使您更容易将列表 B 中的每个值与列表 A 中的每个 Start 和 End 值进行比较,以查看是否有任何重叠(其中只有 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
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用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
        

        【讨论】:

          猜你喜欢
          • 2019-07-08
          • 1970-01-01
          • 2020-11-26
          • 1970-01-01
          • 1970-01-01
          • 2020-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多