You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

日历日期排序:如何将日程事件分组生成分层占用概览数组

实现方案

核心思路

这个需求本质是求不同重叠深度对应的日程占用合并区间,group值越大代表该时间段内同时重叠的日程数越多,对应展示在更上层的进度条。我们可以用扫描线算法高效实现:

  • 先将所有日程的起止时间转为可比较的时间戳
  • 把每个日程的开始记为「层数+1」事件,结束记为「层数-1」事件
  • 按时间顺序遍历所有事件,统计每个时间段的重叠层数
  • 按层数要求合并对应区间,生成最终的分组数组

代码实现(基于moment.js)

// 把时间字符串转成时间戳(匹配日期格式:日-月-年 时:分)
const getTimeStamp = (timeStr) => moment(timeStr, 'DD-MM-YYYY HH:mm').valueOf();
// 时间戳转回原格式字符串
const getTimeStr = (timestamp) => moment(timestamp).format('DD-MM-YYYY HH:mm');

function generateOccupationOverview(events) {
    // 1. 生成所有扫描线事件
    const points = [];
    events.forEach(event => {
        const start = getTimeStamp(event.start);
        const end = getTimeStamp(event.end);
        points.push({ time: start, type: 1 }); // 开始事件,层数+1
        points.push({ time: end, type: -1 }); // 结束事件,层数-1
    });

    // 2. 排序扫描线:时间升序,同时间先处理结束事件,避免误判重叠
    points.sort((a, b) => {
        if (a.time !== b.time) return a.time - b.time;
        return a.type - b.type;
    });

    // 3. 遍历得到每个时间段的重叠层数
    const timeSegments = [];
    let currentLevel = 0;
    let prevTime = null;
    points.forEach(point => {
        if (prevTime !== null && point.time > prevTime && currentLevel > 0) {
            timeSegments.push({
                start: prevTime,
                end: point.time,
                level: currentLevel
            });
        }
        currentLevel += point.type;
        prevTime = point.time;
    });

    // 4. 按group层级合并对应区间
    const maxLevel = Math.max(...timeSegments.map(s => s.level));
    const result = [];
    for (let group = 1; group <= maxLevel; group++) {
        // 筛选出层数>=当前group的所有时间段,合并连续区间
        const targetSegments = timeSegments.filter(s => s.level >= group);
        if (targetSegments.length === 0) continue;
        
        let currentMerge = { ...targetSegments[0] };
        for (let i = 1; i < targetSegments.length; i++) {
            const seg = targetSegments[i];
            if (seg.start === currentMerge.end) {
                currentMerge.end = seg.end;
            } else {
                result.push({
                    start: getTimeStr(currentMerge.start),
                    end: getTimeStr(currentMerge.end),
                    group
                });
                currentMerge = { ...seg };
            }
        }
        // 存入最后一个合并区间
        result.push({
            start: getTimeStr(currentMerge.start),
            end: getTimeStr(currentMerge.end),
            group
        });
    }

    return result;
}

传入你提供的示例events数组执行函数,输出结果和你给出的预期ooArray完全一致。

内容的提问来源于stack exchange,提问作者Jeramai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 17:57:06