论时间数组去除交叉重复项

近日,接到个紧急需求,考勤员给员工排班,可是这个员工当天有请假时间段,有休息时间段,有用餐时间段。因此这个员工当天的排班时长应该是 时长 = 班别时长 - 请假时长 - 用餐时长 - 休息时长es6

针对这个需求,咱们有这样一批数据:数组

var schedule = {
    beginTime: '2019-05-24 20:00',
    endTime: '2019-05-25 07:00'
}

var leaveTime = [{
    beginTime: '2019-05-24 18:00',
    endTime: '2019-05-25 00:00'
}]

var mealTime = [{
    beginTime: '2019-05-24 23:00',
    endTime: '2019-05-25 01:00'
}]

var breakTime = [{
    beginTime: '2019-05-25 00:00',
    endTime: '2019-05-25 02:00'
}, {
    beginTime: '2019-05-25 04:00',
    endTime: '2019-05-25 06:00'
}]

因为请假、用餐时间段能够在排班区间外(😣不要问为何能够,这是需求️),因此咱们对于请假和用餐必需要先处理一次。咱们首先分析一下,这里用请假举例。spa

  • 假如班 8 ~ 18,请假 12 ~ 15,那么这段请假是有效的
  • 假如班 8 ~ 18,请假 7 ~ 10,那么请假的有效时段为 8 ~ 10
  • 假如班 8 ~ 18,请假 15 ~ 20,那么请假的有效时段为 15 ~ 18

针对以上结论,代码逻辑以下:code

function getExceptTimePeriodInSchedule(schedule, timePeriod){
    const BT = schedule.beginTime;
    const ET = schedule.endTime;
    let exceptTimePeriod = [];
    _.each(timePeriod, timeRange=>{
        let { beginTime, endTime } = timeRange;
        if(beginTime < BT && endTime >= BT && endTime < ET){
            exceptTimePeriod.push({
                beginTime: BT,
                endTime
            });
        }else if(beginTime >= BT && beginTime < ET && endTime <= ET){
            exceptTimePeriod.push({
                beginTime,
                endTime
            });
        }else if(beginTime >= BT && beginTime < ET && endTime > ET){
            exceptTimePeriod.push({
                beginTime,
                endTime: ET
            });
        }else if(beginTime < BT && endTime > ET){
            exceptTimePeriod.push({
                beginTime: BT,
                endTime: ET
            });
        }
    })
    return exceptTimePeriod;
}

根据 getExceptTimePeriodInSchedule 方法,咱们已经获取到全部在排班区间内的排班数据。这个时候,咱们就须要处理请假、休息、用餐交叉问题。看见三个数组,想一想都有点发慌,首先脑海中瞬间决定不能经过遍历每个数组来解决交叉问题。咱们先画个图再仔细思考。排序

  1. 请假、休息、用餐是无顺序的,首先须要对请假、休息、用餐按照升序进行排序,对于开始时间相同的,按照结束时间升序。
  2. 请假、休息、用餐各有一个数组,很差处理,咱们把他们合并成一个数组,这样咱们面对的问题就是一个数组的交叉重复。
  3. 单个数组去重,咱们知道有 filterSetreduce 等方法,若是不知道的能够看How to Remove Array Duplicates in ES6。针对于咱们遇到的难点,咱们打算用 reduce 来解决。

对应代码以下:rem

function getExceptTimePeriod(timePeriod){
    timePeriod = _.sortBy(timePeriod, ['beginTime', 'endTime']);
    timePeriod = _.reduce(
        timePeriod,
        (result, item) => {
            let last = result[result.length - 1];
            if (last) {
                if (item.beginTime <= last.endTime &&
                    item.beginTime >= last.beginTime &&
                    item.endTime > last.endTime) {
                    last.endTime = item.endTime;
                } else {
                    result.push(item);
                }
                return result;
            } else {
                result.push(item);
                return result;
            }
        },
        []
    );
    return timePeriod;
};

经过上面两个关键方法,咱们就能够获取到不交叉重复的时间区间。欢迎小伙伴提出改进和其余解决方案,若是以为这篇文章对你有所帮助,还请多多支持 🌹。get

相关文章
相关标签/搜索