比如:a = [
['2022-5-1', '2022-5-5'],
['2022-5-3', '2022-5-10'],
['2022-6-1', '2022-6-5'],
]
那么最终并集应该是:
a = [
['2022-5-1', '2022-5-10'],
['2022-6-1', '2022-6-5'],
]
比如:a = [
['2022-5-1', '2022-5-5'],
['2022-5-3', '2022-5-10'],
['2022-6-1', '2022-6-5'],
]
那么最终并集应该是:
a = [
['2022-5-1', '2022-5-10'],
['2022-6-1', '2022-6-5'],
]
function mergeDates (dates = []) {
return Array.from(dates)
.sort(([m], [n]) => Date.parse(m) - Date.parse(n))
.reduce(
(merged, date) => {
const last = merged[merged.length - 1] ?? [];
const [, l1] = last.map(Date.parse), [d0, d1] = date.map(Date.parse);
if (!(l1 >= d0)) {
merged.push(date);
}
else
if (l1 <= d1) {
last[1] = date[1];
}
return merged;
},
[],
);
}
const unionData = (arr)=>{
if(arr.length<2) return arr;
arr = [...arr].sort((a,b)=>new Date(a[0]) - new Date(b[0]))
return arr.slice(1).reduce((ar, period)=>{
const lastItemEnd = ar[ar.length-1][1]
if(new Date(period[0])<new Date(lastItemEnd)) {
if(new Date(period[1])>new Date(lastItemEnd)) {
ar[ar.length-1][1] = period[1]
}
} else {
ar.push(period)
}
return ar
}, arr.slice(0,1))
}
这是先排序的处理办法
function mergeDate(list) {
return list
// 用 Date.parse 把字符串计算成可以比较的数值
// 但为了能保留原值,所以分别用 origin 和 value 来保存原值和解析后的值
.map(([begin, end]) => ({
origin: [begin, end],
value: [Date.parse(begin), Date.parse(end)]
}))
// 按起始时间排序,排序之后合并过程会更简单
.sort((a, b) => (a.value[0] - b.value[0]))
// 合并过程,
.reduce((acc, it) => {
// 在已处理的列表中查找可以合并的数据,只有最后 1 顶才存在合并的可能
// 证明:如果倒数第 2 项(设为 t2)也可以合并,则新项(设为 n)与之关系:n.begin <= t2.end,
// 因为已经排过序,所以最后一顶(设为 t1),有 t1.begin < n.begin,
// 可得 t1.bgin < t2.end。如果是这样,那么 t1 已经合并入 t2,不会存在 t1
const last = acc[acc.length - 1];
// 上面的证明也说明了比较逻辑,即 n.begin <= t1.end 的时候,存在交集,可合并
if (last && last.value[1] >= it.value[0]) {
last.origin[1] = it.origin[1];
last.value[1] = it.value[1];
} else {
// 不可合并的时候,作为一个新项加入结果集
acc.push(it);
}
return acc;
}, [])
// 最后把原值数组拿出来用,其他的辅助数据不再需要
.map(({ origin }) => origin);
}
为了保留之前的顺序,这里有一个不排序的办法(顺便给个用例)
const a = [
["2022-5-1", "2022-5-5"],
["2022-5-3", "2022-5-10"],
["2022-4-3", "2022-4-5"],
["2022-4-7", "2022-4-10"],
["2022-4-5", "2022-4-7"],
["2022-6-1", "2022-6-5"],
];
function mergeDate(list) {
// 还是先把值解析出来用于计算,原值和解析值都保留着
list = list.map(([begin, end]) => ({ origin: [begin, end], value: [begin, end].map(Date.parse) }));
// 从第 1 项开始,与之前的所有项进行比较
for (let i = 1; i < list.length; i++) {
const next = list[i];
// 与之前的所有项进行比较
for (let j = 0; j < i; j++) {
const it = list[j];
// 比较就是简单的判断是否存在交集
if (next.value[0] >= it.value[0] && next.value[0] <= it.value[1]) {
// 如果存在交集,合并。即更新找到的那个节点的结束时间
it.origin[1] = next.origin[1];
it.value[1] = next.value[1];
// 再将当前节点 (next) 删除掉(因为已经合并了)
list.splice(i, 1);
// 由于合并目标节点的结时间变了,要从这个节点之后重新判断是否有交集
// 如果把 i 重置到目标节点,这样下次循环会从目标节点的下一个开始
i = j;
// 当然合并之后节点在子循环中不需要再去处理了
break;
}
}
}
return list.map(({ origin }) => origin);
}
13 回答12.8k 阅读
7 回答1.9k 阅读
3 回答1.1k 阅读✓ 已解决
2 回答1.2k 阅读✓ 已解决
6 回答873 阅读✓ 已解决
6 回答1k 阅读
2 回答1.3k 阅读✓ 已解决
你这个用原生JS处理会很麻烦,建议借助第三方JS工具库来处理,如day.js、moment.js、XDate等专门处理日期时间的。