2016-12-14 64 views
3

以多維數組如PHP尋找差距過N年跨多日的課程範圍

array(
    array('begin' => '2006-01-01', 'finish' => '2006-02-28'), 
    array('begin' => '2006-03-01', 'finish' => '2006-06-30'), 
    array('begin' => '2006-08-01', 'finish' => '2007-12-30'), 
    array('begin' => '2007-01-01', 'finish' => '2016-12-30'), 
); 

我試圖找出最好的方式來處理數組中的第N個數量有不同程度的範圍和重疊以查看在N年期間是否存在差距。我目前的要求是下到本月。但是我現在根本無法把這個包裹起來。沒有經過一系列嵌套的惡意攻擊,最終將我描繪在一個角落,並且在更大的數據集上進行處理是昂貴的。

+0

N個元素將按照您的示例中的順序排列嗎? –

+0

沒有100%的保證,爲了沒有。我可能不得不採取額外的步驟以某種方式進行排序,如果需要的話,我最終尋找思路或方法的人曾用來嘗試找出我需要做的,以實現類似的目標 – chris

+0

你到底要怎麼「缺口「在你的例子中定義/返回?只需「有一定的差距是/否」或「有X差距」或「有2006-06-30 2006-08-01和之間的差距」? – rlanvin

回答

0

此代碼是希望在O(N),並假定它是一個有序陣列作爲例子。

我用這個日期格式,可以按照字符串進行比較,並給出了相同的結果,因爲如果你想與複雜的Date對象的工作。

// $a is your multidimensional array as above 

$gap = array(); 
for($i=1; $i<sizeof($a); $i++){ 
    $gap[$i] = $a[$i-1]['finish'] < $a[$i]['begin']; 
} 

$gap包含數組或布爾值,其指示在該索引存在差距。

+0

是的這些將作爲字符串進行比較,但我總體上對任何干淨開放。 – chris

+0

連續幾天算缺口? (例如,30日結束,例如31日開始)如果沒有,我在代碼中錯過了一些東西。 –

+0

我希望他們,但在這一點的下個月是可以接受的。 – chris

0

我不會建議一個實際的實施,但更多的是一般的方法。

你通常可以看到這樣那樣的問題兩種方式:

  1. 讓超級智能的代碼。使用遞歸合併重疊範圍的算法,給你留下一系列離散範圍。如果數組中有多行,則會有間隙,並且在範圍的結尾和另一個範圍的開頭之間定義了間隙。這裏的關鍵字是遞歸地
  2. 製作超級笨編碼。用你的間隔的所有月份(不能太多,甚至10年只有120個月)作爲關鍵字創建一個assoc數組,作爲值「真」。迭代你的數組,並將出現在範圍內的月份設置爲「false」。使用array_filter和ta-dah!你留下的月份有差距。這裏的關鍵是不要使用date相關的函數(它們很慢),而只是用算術方法來解釋它。

希望這有助於把你在正確的軌道上。

0

沒有得到廣泛的測試,需要一些重構,但是這是最好的算法,我能想出(我已經做了數據庫實際上類似的東西):

define('DAY_SEC', 86400); 
$result = []; 
foreach ($dates as $date) { 
    $begin = strtotime($date['begin']); 
    $finish = strtotime($date['finish']); 

    $merged = null; 
    foreach ($result as $idx => $span) { 
     if ($span['begin'] <= $finish + DAY_SEC && $span['finish'] >= $begin - DAY_SEC) { 
      if (isset($merged)) { 
       $min = min($span['begin'], $begin, $result[$merged]['begin']); 
       $max = max($span['finish'], $finish, $result[$merged]['finish']); 
       unset($result[$idx]); 
      } else { 
       $min = min($span['begin'], $begin); 
       $max = max($span['finish'], $finish); 
       $merged = $idx; 
      } 

      $result[$merged] = ['begin' => $min, 'finish' => $max]; 
     } 
    } 

    if (!isset($merged)) { 
     $result[] = ['begin' => $begin, 'finish' => $finish]; 
    } 
} 

foreach ($result as &$span) { 
    $span['begin'] = date('Y-m-d', $span['begin']); 
    $span['finish'] = date('Y-m-d', $span['finish']); 
} 

這將導致持續的時間跨度的陣列。它會逐個添加時間片,並在與之前添加的所有內容重疊時將它們合併。如果它重疊多個週期,則會將連續匹配合併到第一個週期中。