英文:
How could I compute a list of "open hours" in javascript from a list of start and end times with overlaps?
问题
const 周一营业时间 = [
{ 开始: "09:00", 结束: "14:00" },
{ 开始: "10:00", 结束: "15:00" },
{ 开始: "17:00", 结束: "23:00" },
];
const 计算后的周一营业时间 = [
{ 开始: "09:00", 结束: "15:00" },
{ 开始: "17:00", 结束: "23:00" },
];
英文:
I am trying to simplify a list of open times so that there are no overlaps/duplicate information showing (in javascript).
Here is an example of what I am trying to achieve:
The starting array would look something like this:
const mondayHours = [
{ start: "09:00", end: "14:00" },
{ start: "10:00", end: "15:00" },
{ start: "17:00", end: "23:00" },
];
And the data is currently displayed like:
Open: 9am-2pm, 10am-3pm, 5pm-11pm
I want the result to return an array for the total open hours like so:
const computedMondayHours = [
{ start: "09:00", end: "15:00" },
{ start: "17:00", end: "23:00" },
];
And so that the data will be displayed like:
>Open: 9am-3pm, 5pm-11pm
I have found a solution online that returns the latest open times with the earliest close times, thinking I could convert it for my uses, but that has not worked at all:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const hours = [{
start: "09:00",
end: "14:00"
},
{
start: "10:00",
end: "15:00"
},
{
start: "17:00",
end: "23:00"
}
]
const isBetween = (value, start, end) => value > start && value < end
const computeOpenHours = (dayHours) => {
const index = {}
dayHours.forEach(({
start: aStart,
end: aEnd
}) => {
dayHours.forEach(({
start: bStart,
end: bEnd
}) => {
aStart = isBetween(bStart, aStart, aEnd) && bStart > aStart ? bStart : aStart
aEnd = isBetween(bEnd, aStart, aEnd) && bEnd < aEnd ? bEnd : aEnd
})
const key = `${aStart}-${aEnd}`
const value = {
start: aStart,
end: aEnd
}
index[key] = index[key] || value
})
return Object.keys(index).map(k => index[k])
}
console.log(computeOpenHours(hours))
<!-- end snippet -->
答案1
得分: 1
你可以减少时间并检查当前开始时间是否大于前一个结束时间。
注意: 这个简单的算法假设输入数组已经排序。
const calcTimeSlots = (workingHours) =>
workingHours.reduce((acc, { start, end }) => {
if (acc.length === 0) {
acc.push({ start, end });
} else {
const latest = acc[acc.length - 1];
if (parseTimeAsMillis(start) > parseTimeAsMillis(latest.end)) {
acc.push({ start, end });
} else if (parseTimeAsMillis(end) > parseTimeAsMillis(latest.end)) {
latest.end = end;
}
}
return acc;
}, []);
const parseTimeAsMillis = (str) =>
str.split(':')
.map((t, i, a) => parseInt(t) * 60 * (a.length - 1))
.reduce((total, curr) => total + curr);
const mondayHours = [
{ start: '09:00', end: '14:00' },
{ start: '10:00', end: '15:00' },
{ start: '17:00', end: '23:00' }
];
const tuesdayHours = [
{ start: '09:00', end: '14:00' },
{ start: '10:00', end: '11:00' }
];
console.log(calcTimeSlots(mondayHours));
console.log(calcTimeSlots(tuesdayHours));
英文:
You can reduce the hours and check if the current start is greater than the prev end time.
Note: This naïve algorithm assumes the input array is already sorted.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const calcTimeSlots = (workingHours) =>
workingHours.reduce((acc, { start, end }) => {
if (acc.length === 0) {
acc.push({ start, end });
} else {
const latest = acc[acc.length - 1];
if (parseTimeAsMillis(start) > parseTimeAsMillis(latest.end)) {
acc.push({ start, end });
} else if (parseTimeAsMillis(end) > parseTimeAsMillis(latest.end)) {
latest.end = end;
}
}
return acc;
}, []);
const parseTimeAsMillis = (str) =>
str.split(':')
.map((t, i, a) => parseInt(t) * 60 * (a.length - 1))
.reduce((total, curr) => total + curr);
const mondayHours = [
{ start: '09:00', end: '14:00' },
{ start: '10:00', end: '15:00' },
{ start: '17:00', end: '23:00' }
];
const tuesdayHours = [
{ start: '09:00', end: '14:00' },
{ start: '10:00', end: '11:00' }
];
console.log(calcTimeSlots(mondayHours));
console.log(calcTimeSlots(tuesdayHours));
<!-- language: lang-css -->
.as-console-wrapper { top: 0; max-height: 100% !important; }
<!-- end snippet -->
Also, here is a related question that I previously answered that may help:
答案2
得分: 0
const hours = [
{"start": "09:00", "end": "14:00"},
{"start": "10:00", "end": "15:00"},
{"start": "17:00", "end": "23:00"}
];
// returns -ve if a<b, 0 if a=b, +ve if a>b
function cmp(a, b) {
return a.replace(':', '') - b.replace(':', '');
}
function mergeIfOverlap({ start: s1, end: e1 }, { start: s2, end: e2 }) {
return cmp(s1, s2) <= 0 && cmp(e1, s2) >= 0 && { start: s1, end: cmp(e1, e2) >= 0 ? e1 : e2 };
}
const result = [...hours].sort(({ start: a }, { start: b }) => cmp(a, b))
.reduce((a, c, _, x, y) => (
x = a.findIndex(i => y = mergeIfOverlap(i, c) || mergeIfOverlap(c, i)),
y && (a[x] = y) || a.push(c), a), []);
console.log(result);
英文:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const hours = [{"start":"09:00","end":"14:00"},
{"start":"10:00","end":"15:00"},
{"start":"17:00","end":"23:00"}]
// returns -ve if a<b, 0 if a=b, +ve if a>b
function cmp(a, b) {
return a.replace(':','') - b.replace(':','')
}
function mergeIfOverlap({start:s1, end:e1}, {start:s2, end:e2}) {
return cmp(s1,s2)<=0 && cmp(e1,s2)>=0
&& {start: s1, end: cmp(e1,e2)>=0 ? e1 : e2}
}
const result = [...hours].sort(({start:a},{start:b})=>cmp(a,b))
.reduce((a,c,_,x,y)=>(
x=a.findIndex(i => y=mergeIfOverlap(i,c)||mergeIfOverlap(c,i)),
y && (a[x]=y) || a.push(c), a), [])
console.log(result)
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论