Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 分割重叠日期范围的最快方法_C#_Split_Overlap_Date Range - Fatal编程技术网

C# 分割重叠日期范围的最快方法

C# 分割重叠日期范围的最快方法,c#,split,overlap,date-range,C#,Split,Overlap,Date Range,我在SQL DB表中有日期范围数据,它有以下三列(仅相关): ID(int-identity) 范围从(仅限日期) 范围至(仅限日期) 对于任何给定的日期范围,可能有任意数量的记录重叠(完全或部分重叠) 条件 每个ID较高的记录(较新的记录)优先于可能重叠(全部或部分)的较旧记录 范围至少为1天(RangeFrom和RangeTo相差一天) 因此,对于给定的日期范围(不超过5年),我必须 获取属于此范围的所有范围记录(全部或部分) 将这些重叠拆分为非重叠范围 返回这些新的非重叠范围 我的看法

我在SQL DB表中有日期范围数据,它有以下三列(仅相关):

  • ID
    (int-identity)
  • 范围从
    (仅限日期)
  • 范围至
    (仅限日期)
对于任何给定的日期范围,可能有任意数量的记录重叠(完全或部分重叠)

条件
  • 每个ID较高的记录(较新的记录)优先于可能重叠(全部或部分)的较旧记录
  • 范围至少为1天(
    RangeFrom
    RangeTo
    相差一天)
  • 因此,对于给定的日期范围(不超过5年),我必须
  • 获取属于此范围的所有范围记录(全部或部分)
  • 将这些重叠拆分为非重叠范围
  • 返回这些新的非重叠范围
  • 我的看法 由于有大量与这些范围相关的复杂数据(大量连接等),并且由于处理器+内存的能力比SQL DB引擎更高效,我决定将重叠数据从DB加载到数据层,并在内存中执行范围截断/拆分。这在开发和执行方面给了我更多的灵活性和速度

    如果您认为这应该在DB中得到更好的处理,请告诉我

    问题: 我想写一个最快的,如果可能的话,也可以是资源不消耗的转换算法。因为我得到了很多这些记录,它们与不同的用户相关,所以我必须为每个用户及其重叠范围数据集运行这个算法

    分割这些重叠范围的最有效(快速且不消耗资源)方法是什么

    示例数据 我有记录
    ID=1
    ID=5
    ,它们以这种方式在视觉上重叠(日期实际上是不相关的,我可以用这种方式更好地显示这些重叠):

    结果应该如下所示:

    111111166666666666664444444444444444444444333333333555555555511111117777777
    
            |666|666666|6666|
            |   |      |4444|444|444444444444|4444444|         |55555|55555|
            |   |222222|2222|222|            |3333333|333333333|33333|     |       |7777777
     1111111|111|111111|1111|111|111111111111|1111111|111111111|11111|11111|1111111|
    
     1234567|890|123456|7890|123|4
    
    
     1 -> 1
     8 -> 1,6
     11 -> 6,2,1
     17 -> 6,4,2,1
     21 -> 4,2,1
     24 -> 4,1
     ...
    
    结果实际上看起来就像我们从顶部看这些重叠,然后从这个自顶向下的视图中得到我们看到的ID

    结果实际上会被转换成新的范围记录,所以旧的ID变得无关紧要。但将使用它们的
    范围从
    范围到
    值(以及所有相关数据):

    111111122222222222223333333333333333333333444444444555555555566666667777777
    

    当然,这只是重叠范围的一个例子。对于任何给定的日期范围,它可以是从0条记录到X的任何内容。正如我们可以看到的那样,范围ID=2被4和6完全覆盖,因此它变得完全过时。

    实际上,您希望对数据进行堆栈,并从堆栈中选择最大值。我以前也曾实施过类似的方法,我们使用的方法比您要求的更灵活,因此可能不适合这样做:

    具有用于管理记录的对象,并将每个记录添加到此对象。添加记录时,创建一个新的日期范围,并将该记录的值与该范围相关联。然后检查该范围是否与任何其他现有范围重叠。如果重叠,则为每个重叠创建一个新范围,并将重叠范围与新范围关联起来(取决于您是在添加每个范围时还是在单个过程中)。这可以在添加数据时完成,也可以在添加所有数据后在一次传递中完成

    最后是一个包含唯一范围的对象,每个范围都有一个与之关联的值集合,有点像上面的图片

    |666|666666|6666| | | |4444|444|444444444444|4444444| |55555|55555| | |222222|2222|222| |3333333|333333333|33333| | |7777777 1111111|111|111111|1111|111|111111111111|1111111|111111111|11111|11111|1111111| |666|666666|6666| | | |4444|444|444444444444|4444444| |55555|55555| | |222222|2222|222| |3333333|333333333|33333| | |7777777 1111111|111|111111|1111|111|111111111111|1111111|111111111|11111|11111|1111111| 然后,您可以为类提供一个扁平化函数(可能使用策略模式),该函数将具有值集合的唯一范围转换为具有单个值的唯一范围,这显然会将最终具有相同值的范围连接起来

    您可能需要一个从每个唯一范围中选择最大值的类,但也可能需要选择最小值、求和、平均值、计数等。每个选项都可以通过传递不同的策略实现来完成


    正如我所说的,这种方法可能比只选择最大值的方法效率低,因为在这种情况下,您不需要将所有值都保留在堆栈中,但正如我所记得的,实现是相当直接的。

    我不太确定这是否有用,但我将采用这种方法。。。 (为了便于理解,首先未进行优化…)

    • 将表映射从[ID->range]转换为[date->list of ID]
    (按日期排序,每个日期-无论是开始还是结束,都是到达下一个日期的时间范围的开始。) 使您的桌子看起来像:

    111111166666666666664444444444444444444444333333333555555555511111117777777
    
            |666|666666|6666|
            |   |      |4444|444|444444444444|4444444|         |55555|55555|
            |   |222222|2222|222|            |3333333|333333333|33333|     |       |7777777
     1111111|111|111111|1111|111|111111111111|1111111|111111111|11111|11111|1111111|
    
     1234567|890|123456|7890|123|4
    
    
     1 -> 1
     8 -> 1,6
     11 -> 6,2,1
     17 -> 6,4,2,1
     21 -> 4,2,1
     24 -> 4,1
     ...
    
    • 选择每个列表中最大的元素
    • 用相同的最大值连接以下记录
    由于最终数据库中会有重复的ID(“在您的示例中,1”被分割为两个段),因此最终最好将数据库保持为日期->ID格式,而不是ID->范围

    现在进行明显的优化——当然,不要在每个日期记录中保留ID列表。只需用空ID填写日期->ID表,在用最终记录填写时,替换迄今为止发现的最大值记录:

    • 创建所有日期条目的表,[日期->ID]
    • 对于原始表中的每条记录:
      • 选择范围从到的日期
      • 如果任何ID值为null或低于当前检查的记录ID,请填写当前ID
    • 然后连接-若下一条记录和上一条记录具有相同的ID,则删除下一条记录
    • 最后,您可能需要对位进行反规范化,而不是为一个范围提取两个连续记录