工作人员安排单独工作的分钟数 [英] Staff schedule working alone minutes

查看:81
本文介绍了工作人员安排单独工作的分钟数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有工作人员的时间清单。我需要找出是否有任何员工一个人在工作,以及他们一天只工作了几分钟?

I have list of times for staff. I need to find out if any of the staff was working alone and how many minutes they were working alone for the day

| 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的帮助,该代码获得了第一个和最后一个单独工作一个人的人,但是这样做并不正确。因为如果有3个人在不同的时间单独工作,那将带来一个问题。 https://3v4l.org/6OmjO

With Andreas' help, following is the code that gets the first and last person who was working alone with alone minutes, but its not quite right. Because if there were 3 people with different times that worked alone, it will give a problem. 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分钟,因为

with following array, you will see the minutes for first user needs to be more then 5 minutes, because he is working alone more at evening.

$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");


推荐答案

我正在完全重写我的答案以便清楚并按正确顺序流动。我对以前的方法做了一些小的改进,但没有什么大不了的。

I am doing a complete re-write of my answer so that it is clear and flows in the proper order. I made a couple of minor refinements from my previous method, but nothing drastic.

首先是数据准备代码。我将OP的 hh:mm 的时间输入和输出值转换为简单的分钟值,同时将员工ID保留为键。

First is the data preparation code. I convert the OP's hh:mm time in and out values to simple minute values, while maintaining employee ids as keys.

// 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]
  ];
*/

这是数据处理代码段。我建立了一个快捷方式-如果一个员工与另一位员工共享相同的轮班,那么第一位员工将立即被视为只有零分钟的时间(很明显)。否则,将一个员工的班次与另一个员工的班次进行比较,以确定他们一个人的工作时间。

This is the data processing snippet. I have built in a shortcut -- if one employee shares an identical shift with another employee, then the first employee is immediately deemed to have zero minutes alone (obviously). Otherwise, an employee's shift is compared one by one against the other employees' shifts to determine how many minutes they are alone.

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()

To help you follow what is happening inside of whittle()


  • 工作人员#1以全班开始从 660 1260 。 ( $ pieces_of_shift 是一个只有一个带有两个元素的子数组的数组-开始分钟和结束分钟)
    $ pieces_of_shift = [[660,1260 ]];

  • 与Staff#2比较后,原始的 $ pieces_of_shift 子数组被替换为两个新的子数组-轮班开始时的单独时间和轮班结束时的单独时间: 660 780 900 1260
    $ pieces_of_shift = [[ 660,780],[900,1260]];

  • 然后将员工3的班次与员工1的剩余两个单独时间范围进行比较。 3号员工的班次不与第一个子数组的任何部分重叠,但在第二个中。这意味着第二个时间范围将被替换,以有效地消除转换时间的重叠。
    $ pieces_of_shift = [[660,780],[900,1020],[1140,1260] ];

  • 这导致员工#1的轮班有3个单独时间段: 660 780 900 1020 1140 1260 。这3个范围的单独时间(每个2小时)产生6个小时的总独奏时间或360分钟。

  • Staff #1 starts with a full shift from 660 to 1260. ($pieces_of_shift is an array with just one subarray with two elements - start minutes and end minutes)
    $pieces_of_shift=[[660,1260]];
  • After being compared against Staff #2, the original $pieces_of_shift subarray is replaced by two new subarrays -- the alone time at the start of the shift, and the alone time at the end of the shift: 660 to 780 and 900 to 1260.
    $pieces_of_shift=[[660,780],[900,1260]];
  • Then Staff #3's shift is compared against both of Staff #1's two remaining ranges of alone time. Staff #3's shift doesn't overlap any part of the first subarray, but it does in the second. This means the second range of time is then replaced to effectively "punch out" the overlap in shift time.
    $pieces_of_shift=[[660,780],[900,1020],[1140,1260]];
  • This results in Staff #1's shift have 3 periods of "alone" time: 660 to 780, 900 to 1020, and 1140 to 1260. These 3 ranges of alone time (2hrs each) yields 6 hours of total solo work or 360 minutes.

这里是带有其他注释的演示

如果特定批次中重复移位的可能性很高或很大,则 whittle()内的总迭代次数可通过以下方式减少 $ colleague_shifts = array_map('unserialize',array_unique(array_map('serialize',$ shifts)))在第一个 foreach()循环。

If there is a high probability or high volume of duplicate shifts in a particular batch, total iterations inside of whittle() can be reduced by writing $colleague_shifts=array_map('unserialize', array_unique(array_map('serialize', $shifts))) before the first foreach() loop.

为此,可以使用相同的多功能方法 来简化多个重复班次的调用 foreach($ shifts ...),但我选择不实施该方法,因为它可能不值得进行卷积。

For that matter, the same multi-functional approach could be used to shortcut several duplicate shifts before the call of foreach($shifts...), but I have chosen not to implement that approach because it may not be worth the convolution.

这篇关于工作人员安排单独工作的分钟数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆