論時間數組去除交叉重複項

近日,接到個緊急需求,考勤員給員工排班,可是這個員工當天有請假時間段,有休息時間段,有用餐時間段。因此這個員工當天的排班時長應該是 時長 = 班別時長 - 請假時長 - 用餐時長 - 休息時長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

相關文章
相關標籤/搜索