我有工作人员的时间列表。我需要知道是否有任何员工单独工作,以及他们当天独自工作多少分钟
| 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,以下是获得第一个和最后一个单独工作的人的代码,但不是很正确。因为如果有3个人在不同的时间独自工作,那就会产生问题。 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 :(得分: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
我花了很长时间才弄明白我需要一个假人。谁知道假人可能有用?
答案 1 :(得分: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()
660
到1260
完全转换。 ($pieces_of_shift
是一个数组,只有一个子数组,包含两个元素 - 开始分钟和结束分钟)$pieces_of_shift=[[660,1260]];
$pieces_of_shift
子阵列被两个新的子阵列所取代 - 换班开始时的单独时间,以及班次结束时的单独时间:{{ 1}}到660
和780
到900
。1260
$pieces_of_shift=[[660,780],[900,1260]];
$pieces_of_shift=[[660,780],[900,1020],[1140,1260]];
到660
,780
到900
,1020
到1140
。这3个单独时间范围(每个2小时)产生6小时的总独奏或360分钟。这是a demo with additional comments。
如果特定批次中存在高概率或大量重复移位,则可以通过在第一个1260
循环之前编写whittle()
来减少$colleague_shifts=array_map('unserialize', array_unique(array_map('serialize', $shifts)))
内的总迭代次数。 / p>
就此而言,在调用foreach()
之前,可以使用相同的多功能方法 来快捷地重复几个重复的班次,但我选择不实施该方法,因为它可能不值得卷积。