
本文介绍如何高效识别日期数组中存在“同日入住与退房”(即某日期同时作为多个预约的起始或结束日)的场景,并自动将其标记为不可用,适用于酒店、日程等时间资源管理场景。
在日历系统或预订管理中,一个常见但易被忽略的业务规则是:若某一天既是某个预约的结束日(checkout),又是另一个预约的开始日(checkin),则该天通常不可对外开放预订——因为实际运营中需预留清洁/交接时间,不允许“无缝衔接”。例如 2023-07-05 同时出现在 {start: "2023-07-03", end: "2023-07-05"} 的 end 字段和 {start: "2023-07-05", end: "2023-07-08"} 的 start 字段中,此时应将 dates 数组中对应 '2023-07-05' 的条目设为 available: false。
实现这一逻辑的关键在于:识别出在 reserved 预约列表中被重复使用的日期(即至少出现两次)。注意,这里“重复”指该日期作为 start 或 end 值出现 ≥2 次,而非连续或成对出现——无论它是两次 start、两次 end,还是一次 start + 一次 end,只要总频次 ≥2,就触发不可用标记。
以下是清晰、高效的实现方案:
✅ 核心思路
- 扁平化提取所有关键日期:遍历 reserved 数组,收集每个对象的 start 和 end 值,合并为一个一维字符串数组 reservedDatesArr;
- 判断重复性:对 dates 中每个日期 obj.date,使用 indexOf() 与 lastIndexOf() 比较——若两者索引不相等,说明该日期在 reservedDatesArr 中至少出现两次;
- 原地更新可用状态:满足条件则设置 obj.available = false。
? 完整可运行代码
const dates = [
{ date: '2023-07-01', available: true },
{ date: '2023-07-02', available: true },
// ...(其余日期省略,见原始数据)
{ date: '2023-07-31', available: true }
];
const reserved = [
{ start: "2023-07-03", end: "2023-07-05" },
{ start: "2023-07-05", end: "2023-07-08" },
{ start: "2023-07-08", end: "2023-07-10" },
{ start: "2023-07-18", end: "2023-07-20" },
{ start: "2023-07-22", end: "2023-07-24" },
{ start: "2023-07-24", end: "2023-07-26" }
];
// 步骤1:提取所有 start/end 日期到扁平数组
const reservedDatesArr = [];
reserved.forEach(({ start, end }) => {
reservedDatesArr.push(start, end);
});
// 步骤2:标记重复出现的日期为不可用
const finalArr = dates.map(obj => {
const idx = reservedDatesArr.indexOf(obj.date);
const lastIdx = reservedDatesArr.lastIndexOf(obj.date);
if (idx !== -1 && idx !== lastIdx) { // 确保存在且重复
obj.available = false;
}
return obj;
});
console.log(finalArr);
// 输出中:'2023-07-05'、'2023-07-08'、'2023-07-24' 的 available 均为 false⚠️ 注意事项与优化建议
- 边界安全:添加 idx !== -1 判断,避免对未匹配日期执行无效比较;
-
性能考量:该方案时间复杂度为 O(n×m)(n 为 dates 长度,m 为 reservedDatesArr 长度),适用于中小型数据集(如单月日历)。若需处理海量预约,建议改用 Map 统计频次(O(n+m)):
const countMap = new Map(); reserved.forEach(({ start, end }) => { countMap.set(start, (countMap.get(start) || 0) + 1); countMap.set(end, (countMap.get(end) || 0) + 1); }); const finalArr = dates.map(obj => ({ ...obj, available: (countMap.get(obj.date) || 0) < 2 })); - 业务语义强化:可根据需求区分“仅 end 重复”或“start/end 同时存在”,此时需分别建两个 Set 再交集判断;
- 日期格式一致性:确保所有日期字符串均为 YYYY-MM-DD 格式(ISO 8601),避免因格式差异导致匹配失败。
通过该方法,你不仅能精准捕获“同日进出”的冲突点,还能以声明式、易维护的方式集成到现有日历逻辑中,显著提升资源调度的准确性与用户体验。










