-1

给定一个包含两个 DateTime 列(StartTime 和 EndTime)的表,以及可能重叠的数据行,我如何找到每个组合的开始/结束块的单个实例?

例如,给定:

  • 07/01/2013 00:00:00, 07/01/2013 12:00:00
  • 07/01/2013 06:00:00, 07/01/2013 18:00:00

我需要一个结果 { 07/01/2013 00:00:00, 07/01/2013 18:00:00 }。该工作可以在 SQL 查询中完成,也可以在 C# 中给定一个如上所述的 DataTable。

4

4 回答 4

1

我能想到的最简单的方法是在您感兴趣的时间范围内删除所有记录,然后根据众所周知的重叠日期公式“合并”记录:

List<Tuple<DateTime, DateTime>> dateRows = GetDateRowsSomehow();
//sorting by start time; you can do this in SQL pretty easily
//necessary to make sure the row most likely to overlap a given row is the next one
dateRows.Sort((a,b) => a.Item1.CompareTo(b.Item1));

for(var i=0; i<dateRows.Count - 1; i++)
    for(var j=i+1, j<dateRows.Count; j++)
        if(dateRows[i].Item1 <= dateRows[j].Item2
            && dateRows[i].Item2 >= dateRows[j].Item1) //overlap
        {
           //keep date row i, with the values of the complete time range of i and j
           dateRows[i].Item1 = dateRows[i].Item1 < dateRows[j].Item1
               ? dateRows[i].Item1
               : dateRows[j].Item1;
           dateRows[i].Item2 = dateRows[i].Item2 > dateRows[j].Item2
               ? dateRows[i].Item2
               : dateRows[j].Item2;
           //remove row j and ensure we don't skip the row after it
           dateRows.RemoveAt(j);
           j--;
        }

此解决方案的 WCS 是一个零重叠的大型结果集,其执行顺序为 N(N-1)/2 = O (N 2 )。最好的情况是线性的(不包括 NlogN 排序操作或 List 内的重复线性移位),当所有有问题的行相互重叠时。您不能使用 foreach,因为我们在移动时会更改集合的大小。可能有一种更有效的方法(例如从后到前遍历列表,最小化移位),但这应该是体面的,而且重要的是,干净简洁。

于 2013-07-09T17:23:25.643 回答
1

您可以使用.NET 的时间周期库来计算不重叠的时间跨度:

// ----------------------------------------------------------------------
public void TimeSpansWithoutOverlap()
{
  // periods
  ITimePeriodCollection periods = new TimePeriodCollection();
  periods.Add( new TimeRange( 
    new DateTime( 2013, 7, 1, 0, 0, 0 ), 
    new DateTime( 2013, 7, 1, 12, 0, 0 ) ) );
  periods.Add( new TimeRange( 
    new DateTime( 2013, 7, 1, 6, 0, 0 ),
    new DateTime( 2013, 7, 1, 18, 0, 0 ) ) );

  ITimePeriodCollection combinedPeriods = new TimePeriodCombiner<TimeRange>().CombinePeriods( periods );
  foreach ( ITimePeriod combinedPeriod in combinedPeriods )
  {
    Console.WriteLine( "Period: " + combinedPeriod );
  }
} // TimeSpansWithoutOverlap
于 2013-09-13T13:33:09.380 回答
0

作为初学者,我会创建 ac# 类并使用 DateTime 操作来查找重叠。至于重叠算法,只需区分开始时间和结束时间。

似乎也在这里完成了检测重叠周期的算法

还有 http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET

于 2013-07-09T17:22:23.347 回答
0

这样的事情应该做你:

select *
from myTable t
where not exists ( select *
                   from myTable overlap
                   where overlap.partial_key = t.partial_key
                     and overlap.dateTimeFrom <= t.dateTimeThru
                     and overlap.dateTimeThru >= t.dateTimeFrom
                 )

这是一个简单的相关子查询。

于 2013-07-09T17:34:20.153 回答