我正在制作MERN堆栈的API,并且在一条重要的路线上挣扎。
这里是我返回的自由插槽的一个例子。
[
{
booked: false,
startAt: 2025-03-03T07:00:00.000Z,
endAt: 2025-03-03T07:15:00.000Z,
},
{
booked: false,
startAt: 2025-03-03T07:15:00.000Z,
endAt: 2025-03-03T07:30:00.000Z,
},
{
booked: false,
startAt: 2025-03-03T07:45:00.000Z,
endAt: 2025-03-03T08:00:00.000Z,
},
{
booked: false,
startAt: 2025-03-03T08:00:00.000Z,
endAt: 2025-03-03T08:15:00.000Z,
},
{
booked: false,
startAt: 2025-03-03T08:15:00.000Z,
endAt: 2025-03-03T08:30:00.000Z,
},
{
booked: false,
startAt: 2025-03-03T10:15:00.000Z,
endAt: 2025-03-03T10:30:00.000Z,
},
{
booked: false,
startAt: 2025-03-03T10:30:00.000Z,
endAt: 2025-03-03T10:45:00.000Z,
}
]并希望将它们重新组合为2或3个连续时隙,如:
//Grouped by 2 with slot3 booked
[[slot1, slot2],[slot4,slot5],[slot5,slot6]]
//Grouped by 3 with all slots free
[[slot1, slot2,slot3],[slot2, slot3,slot4],[slot3, slot4,slot5],[slot4,slot5,slot6]]有人有主意吗?
发布于 2021-04-05 16:14:57
几乎可以肯定,在reduce中有一种稍微更有效的方法,但是这个版本非常简单,对于大多数合理的情况来说,它的性能都足够高:
// utility function
const aperture = (n) => (xs) =>
[...xs .keys ()] .slice (0, 1 - n) .map (i => xs .slice (i, i + n))
// main function
const groupSlots = (n, slots) =>
aperture (n) (slots) .filter (group => group .every (({booked}) => ! booked))
// just to format output
const display = (o) => console .log (JSON.stringify (o, null, 4))
// sample data
const sixSlotsThirdBooked = [{booked: false, startAt: '2025-03-03T07:00:00.000Z', endAt: '2025-03-03T07:15:00.000Z'}, {booked: false, startAt: '2025-03-03T07:15:00.000Z', endAt: '2025-03-03T07:30:00.000Z'}, {booked: true, startAt: '2025-03-03T07:45:00.000Z', endAt: '2025-03-03T08:00:00.000Z'}, {booked: false, startAt: '2025-03-03T08:00:00.000Z', endAt: '2025-03-03T08:15:00.000Z'}, {booked: false, startAt: '2025-03-03T08:15:00.000Z', endAt: '2025-03-03T08:30:00.000Z'}, {booked: false, startAt: '2025-03-03T08:30:00.000Z', endAt: '2025-03-03T08:45:00.000Z'}]
// demo
display (groupSlots (2, sixSlotsThirdBooked))
// sample data
const sixFreeSlots = [{booked: false, startAt: '2025-03-03T07:00:00.000Z', endAt: '2025-03-03T07:15:00.000Z'}, {booked: false, startAt: '2025-03-03T07:15:00.000Z', endAt: '2025-03-03T07:30:00.000Z'}, {booked: false, startAt: '2025-03-03T07:45:00.000Z', endAt: '2025-03-03T08:00:00.000Z'}, {booked: false, startAt: '2025-03-03T08:00:00.000Z', endAt: '2025-03-03T08:15:00.000Z'}, {booked: false, startAt: '2025-03-03T08:15:00.000Z', endAt: '2025-03-03T08:30:00.000Z'}, {booked: false, startAt: '2025-03-03T08:30:00.000Z', endAt: '2025-03-03T08:45:00.000Z'}]
// demo
display (groupSlots (3, sixFreeSlots)).as-console-wrapper {max-height: 100% !important; top: 0}
助手函数aperture (n)沿着数据移动一个长度为n的滑动窗口,例如,aperture (2) (['a', 'b', 'c', 'd'])将产生[['a', 'b'], ['b', 'c'], ['c', 'd']]。
主函数groupSlots,在输入插槽数组上调用aperture,然后过滤掉那些有预定插槽的组。
(我们还包括一个简单的display函数,以避开StackOverflow引入的用于描述包含对某些值的多个引用的对象的稍微奇怪的格式。但这只是一个小的格式化部分。)
更新
在另一项要求之后(请注意,我在对帖子的最初评论中确实提出了这个问题!),我们也可以这样做,但我们需要额外的助手功能来将我们的工作限制在相邻的块上:
// utility functions
const aperture = (n) => (xs) =>
[...xs .keys ()] .slice (0, 1 - n) .map (i => xs.slice(i, i + n))
const last = (xs) =>
xs [xs .length - 1]
const groupWith = (fn) => (xs) =>
xs .reduce (
(r, x, i, a) => i == 0
? [[x]]
: fn (last (last (r)), x)
? [... r .slice (0, -1), [... last (r), x]]
: [...r, [x]],
[]
)
// main function
const groupSlots = (n, slots) =>
groupWith (({endAt}, {startAt}) => endAt == startAt) (slots .filter (({booked}) => ! booked))
.flatMap (
group => aperture (n) (group)
)
// just to format output
const display = (o) => console .log (JSON.stringify (o, null, 4))
// sample data
const slotsWithBreaks = [
{booked: false, startAt: '2025-03-03T07:00:00.000Z', endAt: '2025-03-03T07:15:00.000Z'},
{booked: false, startAt: '2025-03-03T07:15:00.000Z', endAt: '2025-03-03T07:30:00.000Z'},
{booked: false, startAt: '2025-03-03T07:30:00.000Z', endAt: '2025-03-03T07:45:00.000Z'},
{booked: false, startAt: '2025-03-03T07:45:00.000Z', endAt: '2025-03-03T08:00:00.000Z'},
{booked: false, startAt: '2025-03-03T08:00:00.000Z', endAt: '2025-03-03T08:15:00.000Z'},
{booked: false, startAt: '2025-03-03T08:15:00.000Z', endAt: '2025-03-03T08:30:00.000Z'},
{booked: false, startAt: '2025-03-03T08:30:00.000Z', endAt: '2025-03-03T08:45:00.000Z'},
/* ... coffee break ...*/
{booked: false, startAt: '2025-03-03T09:00:00.000Z', endAt: '2025-03-03T09:15:00.000Z'},
{booked: false, startAt: '2025-03-03T09:15:00.000Z', endAt: '2025-03-03T09:30:00.000Z'},
{booked: false, startAt: '2025-03-03T09:30:00.000Z', endAt: '2025-03-03T09:45:00.000Z'},
{booked: true, startAt: '2025-03-03T09:45:00.000Z', endAt: '2025-03-03T10:00:00.000Z'},
/* ... weekly meeting ... */
{booked: true, startAt: '2025-03-03T11:00:00.000Z', endAt: '2025-03-03T11:15:00.000Z'},
{booked: false, startAt: '2025-03-03T11:15:00.000Z', endAt: '2025-03-03T11:30:00.000Z'},
{booked: false, startAt: '2025-03-03T11:30:00.000Z', endAt: '2025-03-03T11:45:00.000Z'},
{booked: false, startAt: '2025-03-03T11:45:00.000Z', endAt: '2025-03-03T12:00:00.000Z'},
/* ... lunch ... */
// ...
]
// demo
display (groupSlots (3, slotsWithBreaks)).as-console-wrapper {max-height: 100% !important; top: 0}
我们添加了一个简单的实用函数last,,它返回数组中的最后一个元素。我们在groupWith,中使用last,它接受一个谓词,并返回一个函数,该函数根据谓词在提供两个连续数组元素时是否返回true,将数组的元素组合在一起。
然后更新我们的主要函数,将时隙分解为(未预订的)时隙的连续数组,并对这些时隙调用aperture,将结果平面映射到一个数组中。请注意,由于我们已经必须根据不可预订的插槽将输出数组分开,所以最简单的方法是先删除预定的插槽,而不是在早期版本中使用检查,即组中的所有插槽实际上都没有预订。
我对groupWith的这种实现并不感兴趣,我认为可能还有更优雅的东西。但我认为它能胜任这项工作。
https://stackoverflow.com/questions/66955208
复制相似问题