2017-07-17 72 views
-1

我有工作人員的時間列表。我需要找出是否有任何工作人員的單獨工作,多少分鐘,他們一天工作時間表單獨工作分鐘

| staff| start | end | 
|:--- |:--- |:--- | 
| 1 | 11:05 | 20:00 | 
| 2 | 11:00 | 17:00 | 
| 3 | 19:00 | 03:00 | 
| 4 | 13:00 | 20:00 | 
| 5 | 19:00 | 03:00 | 

隨着Andreas' help單獨工作,以下是得到誰與單獨工作的第一和最後一個人的代碼單獨一分鐘,但不完全正確。因爲如果有三個人在不同的時間單獨工作,這會產生問題。 https://3v4l.org/6OmjO

$staff = array(1,2,3,4,5); 
$start = array("11:05", "11:00", "19:00", "13:00", "19:00"); 
$end = array("20:00", "17:00", "03:00", "20:00", "03:05"); 

array_multisort($start, $end, $staff); 

$aloneStart = (strtotime($start[1]) - strtotime($start[0]))/60; // first and second items are the ones that may be working alone at start 
$aloneEnd = (strtotime($end[count($end) - 1]) - strtotime($end[count($end) - 2]))/60; // last and second to last are the ones that may be working alone at end 

if ($aloneStart > 0) 
{ 
    $staffAloneStart = $staff[0]; //must be the first who worked alone 
    echo "minutes alone at start: " . $aloneStart . " and it was " . $staffAloneStart . "\n"; 
} 

if ($aloneEnd > 0) 
{ 
    $staffAloneEnd = $staff[count($end) - 1]; // must be the last to end that worked alone 
    echo "minutes alone at end: " . $aloneEnd . " and it was " . $staffAloneEnd . "\n"; 
} 

$aloneTime = intval($aloneStart) + intval($aloneEnd); 
echo "total time alone " . $aloneTime; 

與下面的數組,你會看到分鐘首先用戶需要更多然後5分鐘,因爲他是在晚上獨自更多的工作。

$staff = array(1, 2, 3, 4, 5); 
$start = array("11:05", "11:10", "19:00", "13:00", "19:00"); 
$end = array("20:00", "17:00", "03:00", "16:00", "03:00"); 
+0

@mickmackusa添加日期不是問題,是我感到困惑的計算。因爲我們必須跟蹤所有工作人員,這可能是單獨工作的時間,並計算他/她單獨工作的分鐘數。 – Basit

+0

@mickmackusa我理解他的兩個問題的方式,輸出應該是告訴他誰有一個人待了多久。你如何呈現它可能不是那麼重要,因爲他似乎能夠改變你的輸出到他想要的東西。我可能是錯的,但這就是我對Basit的理解。他還有很多關於PHP的問題和答案,所以我認爲他可以處理你給他的任何輸出。 – Andreas

+0

熱切期待... – Basit

回答

1

我正在做一個完整的重寫我的答案,以便清楚並按正確的順序流動。我從之前的方法做了一些小修改,但沒有太大的改進。

首先是數據準備代碼。我將OP的hh:mm時間輸入和輸出值轉換爲簡單的分鐘值,同時將員工ID保持爲鍵。

// My test data in OP's format to start with: 
$staff=[1,2,3]; 
$start=['11:00','13:00','17:00']; 
$end=['21:00','15:00','19:00']; 

// My data preparation method: 
foreach($staff as $i=>$v){ 
    $on=explode(':',$start[$i]); // separate hh from mm of start of shift 
    $on_minutes=$on[0]*60+$on[1]; // calculate total minutes from start of day 
    $off=explode(':',$end[$i]); // separate hh from mm of end of shift 
    $off_minutes=($off[0]+($on[0]>$off[0]?24:0))*60+$off[1]; // calculate minutes from start of day, factoring shift that run past midnight 
    $shifts[$v]=[$on_minutes,$off_minutes]; // store prepared data for future processes 
} 
/* 
    (new prepared array): 
    $shifts=[ 
    1=>[660,1260], 
    2=>[780,900], 
    3=>[1020,1140] 
    ]; 
*/ 

這是數據處理片段。我建立了一條捷徑 - 如果一名員工與另一名員工共享相同的班次,那麼第一名員工立即被視爲只有零分鐘(顯然)。否則,將員工的班次逐一與其他員工的班次進行比較,以確定他們單獨工作的時間。

function whittle($colleague_shifts,$pieces_of_shift){ // initially, PoS is only one element 
    foreach($colleague_shifts as $k=>$cs){ 
     foreach($pieces_of_shift as $i=>$ps){ 
      if($cs[0]<=$ps[0] && $cs[1]>=$ps[1]){ 
       unset($pieces_of_shift[$i]); 
       continue; // fully covered by coworker 
      } 
      $temp=[]; 
      if($ps[0]<$cs[0] && $cs[0]<$ps[1]){ 
       $temp[]=[$ps[0],$cs[0]]; // push new unmatched start into temp PoS array 
      } 
      if($ps[1]>$cs[1] && $cs[1]>$ps[0]){ 
       $temp[]=[$cs[1],$ps[1]]; // push new unmatched end into temp PoS array 
      } 
      if($temp){ 
       array_splice($pieces_of_shift,$i,1,$temp); // replace the current PoS with 1 or 2 new PoS subarrays 
      } 
     } 
     if(!$pieces_of_shift){ 
      return 0; // no minutes alone 
     } 
    } 
    // subtract all end alone minutes from all start alone minutes 
    return array_sum(array_column($pieces_of_shift,1))-array_sum(array_column($pieces_of_shift,0)); 
} 

foreach($shifts as $id=>$s){ 
    $colleague_shifts=array_diff_key($shifts,[$id=>'']); // generate array excluding target worker's shift 
    if(in_array($s,$colleague_shifts)){ // check for same start and end times elsewhere 
     $alone[$id]=0; // exact duplicate allows shortcut as "never alone" 
    }else{ 
     $alone[$id]=whittle($colleague_shifts,[$s]); // whittle down times where target employee is alone 
    } 
} 
var_export($alone); 

輸出:

array (
    1 => 360, // alone from 11am-1pm, 3pm-5pm, and 7pm-9pm 
    2 => 0, // never alone 
    3 => 0, // never alone 
) 

爲了幫助您遵循什麼是whittle()

  • 人員#1開始從6601260整個班次內發生的事情。 ($pieces_of_shift是隻用一個子陣列具有兩個元件的陣列 - 開始分鐘和結束分鐘)
    $pieces_of_shift=[[660,1260]];
  • 針對工作人員#2進行比較後,原來的$pieces_of_shift子陣列由兩個子陣列的新替換 - 在單獨時間在開始以及在班次結束時的單獨時間:6607809001260
    $pieces_of_shift=[[660,780],[900,1260]];
  • 然後將員工#3的班次與員工#1剩餘的兩個單獨時間範圍進行比較。員工#3的轉變不會與第一個子陣列的任何部分重疊,但在第二個子陣列中。這意味着第二個時間範圍被替換以有效地「移出」移位時間的重疊。
    $pieces_of_shift=[[660,780],[900,1020],[1140,1260]];
  • 這導致工作人員#1的轉移具有的 「獨」 時間3個時期:6607809001020,並11401260。這3個單獨的時間範圍(每個2小時)產生總共6小時的獨奏工作或360分鐘。

這是a demo with additional comments


如果有一個高概率或特定批次的重複位移的高容量,可以通過第一foreach()循環之前寫入$colleague_shifts=array_map('unserialize', array_unique(array_map('serialize', $shifts)))可以減少whittle()內部總迭代。

對於這個問題,同樣的多功能方法可以使用的foreach($shifts...)呼叫前幾個快捷方式的變化重複,但我選擇不執行該方法,因爲它可能不值得卷積。

+0

我不知道我理解你的「時代」。如果我要將它們轉換回「正常」,這是否正確? https://3v4l.org/f0s9u只是爲了確保我的第一行代碼正確。第二天27 = 03:00。 – Andreas

+0

它已經從OP非常安靜。我也只是想知道我們的答案是否有問題。他們兩人似乎都有效。我不認爲有太多的性能差異。這只是一個輸出問題,據我所知 – Andreas

+0

@Andreas抱歉,傢伙,在過去2天旅行..今天要測試並實施一個可以輕鬆分解成小函數或其他..必須做的事情phpunit測試也爲它。但不管...我真的很感激幫助。 – Basit

1

明白了!

這花了一些時間,但我找到了解決方案。
設法找到mickmacks測試用例的解決方案。
這是一個十人案例,它似乎也支持這一點。

<?php 
$staff = array(1,2,3,4,5,6,7,8,9,10); 
$start = array("11:00", "13:00", "17:00", "17:00", "11:00", "13:30", "16:50", "18:30","17:00", "11:00"); 
$end = array("21:00", "15:00", "19:00", "19:30", "11:30", "15:10", "18:45", "19:45", "19:00", "11:30"); 

// Add staff number to end of time ex 11:00 => 11:00#2 
For($i=0; $i<count($start);$i++){ 
    $start[$i] .= "#" . $staff[$i]; 
    $end[$i] .= "#" . $staff[$i]; 

} 
$t = array_merge($start,$end); // create one long array with all in and out times 
sort($t); 
//var_dump($t); 
// Multisport is needed to get all arrays in time order as reference 
array_multisort($start, $end, $staff); 

// Find first start time (11:00) and slice array thwre, build string 
$test = implode(PHP_EOL,array_slice($t, array_search($start[0], $t))); 

// Find the times before first start (night end times) and add them last in string 
$test .= PHP_EOL . implode(PHP_EOL,array_slice($t, 0,array_search($start[0], $t))); 
$times = explode(PHP_EOL, $test); // explode to make it array again 
// Var_dump($times); 

$WhoIsInDaHouse = array("dummy"); // add a dummy variable since 0=false in later if 
$j=0; 
for($i=0; $i<count($times);$i++){ 
    //echo $times[$i] ." " . $i ."\n"; 
    if($times[$i]){ 
     $TimePerson = explode("#", $times[$i]); 
     $Time = $TimePerson[0]; 
     $person = $TimePerson[1]; 


     $inout = array_search($person, $WhoIsInDaHouse); //is person in house and about to leave? 
     If($inout != false){ //if person enter work false, if true: key of person leaving in $WhoIsInDaHouse 
      //Here $person is leaving work 
      Unset($WhoIsInDaHouse[$inout]); 

      If(count($WhoIsInDaHouse) == 2){ // someone will now be alone since we have a dummy 
       $Alone[$j]["start"] = $Time; 
       $Alone[$j]["who"] = array_slice($WhoIsInDaHouse, -1)[0]; 
      }elseif(count($WhoIsInDaHouse) == 1 && $prevcount == 2){ 
       // Only dummy left 
       $Alone[$j]["end"] = $Time; 
       $Alone[$j]["duration"] = strtotime($Alone[$j]["end"])-strtotime($Alone[$j]["start"]); 
       $j++; 
      } 
     }Else{ 
      // Here person enters work 
      $WhoIsInDaHouse[] = $person; 

      If(count($WhoIsInDaHouse) == 2){ // someone is entering alone 
       $Alone[$j]["start"] = $Time; 
       $Alone[$j]["who"] = $person; 
      }elseif(count($WhoIsInDaHouse)>2 && $prevcount == 2){ // not alone anymore 
       $Alone[$j]["end"] = $Time; 
       $Alone[$j]["duration"] = strtotime($Alone[$j]["end"])-strtotime($Alone[$j]["start"]); 
       $j++; 
      } 
     } 
     $prevcount = count($WhoIsInDaHouse); 
    } 
} 
foreach($Alone as $key => &$loner){ 
    if($loner["duration"]==0) unset($Alone[$key]); 
} 
Var_dump($Alone); 

而且看到美女運行https://3v4l.org/bT2bZ

我花了很長的時間來找出我需要一個假人。誰知道假人可能有用?

+0

而陣列中有一個額外的項目的原因是因爲我有兩個人在同一時間開始。所以,只有一個人是獨自一人,但因爲下一次開始的時間是零。 – Andreas

+0

不知何故,這個簡單的事情變得很難做到哈哈,即使是我自己仍然堅持找到一個簡單的解決方案。 – Basit

+0

@mickmackusa哇...這很奇怪。似乎for循環運行一次。如果我回復$ times [$ i],它會迴應一個空的。如果我儘早停止循環,那麼它對你的例子有效,但對五個人不起作用。所以有些奇怪的事發生了。我只是添加了一個if($ times [$ i]),並且這個問題看起來很糟糕。感謝您指出! :-) – Andreas