2017-09-05 64 views
1

我正在研究算法以計算多個日期範圍的連續重疊。它也需要有一定的重疊次數。對於下面的示例圖片,我需要3個日期不斷重疊。有效的重疊日期爲8月20日至8月23日,因爲8月24日只有2次重疊。多個日期範圍的連續重疊C#

我已經嘗試了許多方法,包括循環遍歷所有日期,並將每一個與下一個進行單獨比較。該代碼看起來像這樣。

這裏是一個.net提琴更好的可視化:https://dotnetfiddle.net/x3LfHR#

private bool Compare(CompareDate a, CompareDate b) 
    { 
     DateTime? tStartA = a.ActiveDate; 
     DateTime? tEndA = a.ExpireDate; 
     DateTime? tStartB = b.ActiveDate; 
     DateTime? tEndB= b.ExpireDate; 

     bool overlap = (tStartA <= tEndB || tEndB == null) && (tStartB <= tEndA || tEndA == null); 

     DateTime? overlapStart = null; 
     DateTime? overlapEnd = null; 

     if (overlap) 
     { 
      //Find maximum start date. 
      overlapStart = (tStartA >= tStartB) ? tStartA : tStartB; 
      //Find Min End date between the two 
      overlapEnd = (tEndA <= tEndB) ? tEndA : tEndB; 

      if (overlapStart > this.overlapStart || this.overlapStart == null) 
      { 
       this.overlapStart = overlapStart; 
      } 
      if (overlapEnd < this.overlapEnd || this.overlapEnd == null) 
      { 
       this.overlapEnd = overlapEnd; 
      } 

但是,這種方法很難找出連續的重疊日期。我試圖在https://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET上使用.Net時間段庫,但與我的情況無關。任何幫助表示讚賞。

enter image description here

+0

這似乎與[此問題]非常相似(https://stackoverflow.com/q/13513932/215552)。它的答案對你有幫助嗎? –

+0

是的,我已經用這個問題的一些方面來比較兩個日期。但是,由於這是多個日期的連續重疊,因此更加複雜。 – aoakeson

+0

我_think_我明白。你有一組日期範圍。您需要查找聚合範圍,並且對於該範圍內的每個日期,必須至少有三個重疊的組分範圍。組成範圍的組合可以在所得到的範圍內變化,但是每個日期必須完全由至少三個組成範圍覆蓋,沒有間隙。那是對的嗎?如果是這樣,在你的例子中,8月20 - 22日滿足A,B和D,而8月23日滿足A,C和D,是嗎?假設所有這些都是正確的,那麼算法的輸入和它們的數據類型是什麼? –

回答

1

行 - LINQ來救援!

注意:爲了進行比較,您必須刪除時間組件並嚴格使用唯一的日期(例如DateTime.Date)。根據您的要求,這正是您需要這樣做的方式,所以它不應該成爲問題。

public List<DateTime> CompareDates(List<DateTime[]> compareRanges, int overlapLevel = 1) 
{ 
    var grouped = compareRanges.SelectMany(r => r).GroupBy(d => d); 
    var thresholdMatch = grouped.Where(g => g.Count() >= overlapLevel) 
     .Select(g => g.Key) 
     .OrderBy(d => d) 
     .ToList(); 

    return thresholdMatch; 
} 

你可以在一個樣本控制檯應用程序測試的邏輯,使用下面的框架代碼爲例:

static void Main() 
{ 
    var setA = new[] 
    { 
     new DateTime(2017, 8, 20), 
     new DateTime(2017, 8, 21), 
     new DateTime(2017, 8, 22),  
     new DateTime(2017, 8, 23),  
     new DateTime(2017, 8, 24), 
    }; 

    var setB = new[] 
    { 
     new DateTime(2017, 8, 20), 
     new DateTime(2017, 8, 21), 
     new DateTime(2017, 8, 22), 
    }; 

    var setC = new[] 
    { 
     new DateTime(2017, 8, 22), 
     new DateTime(2017, 8, 23), 
     new DateTime(2017, 8, 24), 
     new DateTime(2017, 8, 25), 
     new DateTime(2017, 8, 26), 
    }; 

    var setD = new[] 
    { 
     new DateTime(2017, 8, 20), 
     new DateTime(2017, 8, 21), 
     new DateTime(2017, 8, 22), 
     new DateTime(2017, 8, 23), 
    }; 

    var compareList = new List<DateTime[]> 
    { 
     setA, setB, setC, setD 
    }; 

    // setting the threshold to 2 will cause 8/24 to be added to the result... 
    // setting this to 1 (default) will return all intersections 
    // for now, set it to 3, per the question! 
    var result = CompareDates(compareList, 3); 
    foreach (var intersectDate in result) 
    { 
     Console.WriteLine(intersectDate); 
    } 
} 

希望這有助於我當然有它的樂趣!

P.S.我分叉你的小提琴:https://dotnetfiddle.net/GUzhjh。 這包含了原始程序的修改版本,所以你應該可以稍微玩一下。

+0

謝謝你,我會盡快試用,並在我的程序中實施。無論如何,加爾德有人對此很開心。 :P – aoakeson

+0

@aoakeson:你應該看看小提琴,那個人有完整的實現邏輯,包括根據你的日期對象創建日期數組。這裏發佈的例子更多的是用於概念理解。 – code4life

+0

就像你說的,如果不需要帶時間的DateTime,這個解決方案就可以工作。不幸的是在我的情況下,時間是必需的。 – aoakeson

0

這裏是一個算法開始:

  • 排序所有的開始和結束日期時間,分配+1到每一個開始和-1到每一個末端。
  • 從間隔開始到間隔結束,聚合上面查找+3值的時間段分配。注意這個日期時間。
  • 繼續前進,直到總價值降至+3以下。
  • Voila! (我想。)記住這一個並繼續處理。
  • 當第二個發生時,然後保存最長並丟棄另一個。
  • 繼續,直到找到結束間隔;並報告結果。