我真的是Dart的新手(刚从本周开始,到目前为止很喜欢),并且将这段JS代码转换为Dart时遇到了很多麻烦。我还担心特定于语言的陷阱可能由于实施不当而将其变成非常缓慢的功能。
我尝试了一些伪箭,但是我无法为实际的实现而烦恼。也许有一些Dart良好经验的人可以帮忙:)
让我先解释一下。
它做什么
需要两个参数:
它所做的是解析对象,以删除不可能计划任务的所有天/小时/分钟(作为起点),这意味着您没有DURATION的连续分钟进行的任务/服务。
示例数据
因此,DURATION
= 20(分钟)。
开始数据(see the pretty print version here, for space purposes):
{"day 1":{"10":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,54,55,56,57,58,59],"11":[0,1,2,3,4,5,6,7,8,9,10,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,55,56,57,58,59],"12":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59],"14":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59],"15":[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33]},"day 2":{"22":[26,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58],"23":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,56,57,58,59]},"day 3":{"00":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]},"day 4":{"13":[0,1,2,3,4,5,6,7,8,9,10]}}
这应该是解析(see the pretty print version here, for space purposes)后的结果:
{"day 1":{"10":[1,2],"11":[30,31,32,55,56,57,58,59],"12":[0,1,2],"14":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]},"day 2":{"22":[38,39],"23":[0,56,57,58,59]},"day 3":{"00":[0]}}
注释(需要转换的代码已将其考虑在内)
尽管上面的示例的duration
为20分钟,但是任务可以持续一个多小时(例如75分钟)。
只能有一个任务(一个)(一个持续时间)。
日子总是井井有条(asc)。
时间总是按顺序(asc)。
分钟总是按顺序(asc)。
一项任务可以在一个小时内开始,而在下一个任务中结束,但是仅,如果两个小时之间没有暂停。例如:14:59 => 15:00(不 14:59 => 16:00)。
一项任务可以在一天中开始,而在下一个任务中可以结束,但是只能在午夜,并且它是对象中的下一个索引(高于该点)。例如:[INDEX] 23:59天=> [INDEX + 1] 00:00天。
实际代码
第一版
我认为评论很清楚。为了计算持续时间,它以[{t: 4}, {t: 5}, {t: 6}, {t: 11}, {t: 12}, {t: 37}]
之类的列表开始,将其反转,然后在下一个分钟数是前一个分钟数的直接前身时,将其连续添加到连胜计数器中。然后将其与值结合起来得到[{t: 4, s: 3}, {t: 5, s: 2}, {t: 6, s: 1}, {t: 11, s: 2), {t: 12, s: 1}, {t: 37, s: 1}]
。使用这种结构,它可以轻松地为那些条纹足够长的人过滤,并重新构造我要寻找的结构。
const schedule = (openings) => {
// Keep track of the day "names"
const days = Object.keys(openings)
// Gather the times into an array with day, hour, and minute properties
// as well as a timestamp that depicts the sequential minute across all days
const minutes = Object.values(openings)
.flatMap((hs, d) =>
Object.entries(hs).flatMap(([h, ms]) =>
ms.map(m => ({ h, d, m, t: d * 60 * 24 + h * 60 + m }))
)
)
//=> [{h: "10", d: 0, m: 1, t: 601}, {h: "10", d: 0, m: 2, t: 602}, ...]
// For each of those minutes, determine how long a block of
// consecutive minutes can be placed there
const durations = minutes.map(x => x.t).slice(0).reverse().reduce(
({ ms, streak, prev }, x) =>
x === prev - 1
? { ms: [...ms, streak + 1], streak: streak + 1, prev: x }
: { ms: [...ms, 1], streak: 1, prev: x },
{ ms: [], streak: 1, prev: -1 }
).ms.reverse()
// Combine minutes and durations into a single list
const schedule = minutes.map((m, i) => ({ ...m, s: durations[i] }))
//=> [{h: "10", d: 0, m: 1, t: 601, s: 3}, {h: "10", d: 0, m: 2, t: 602,s: 2}, ...]
// Return a function that selects all starting slots for a
// task that requires `duration` minutes.
return (duration) =>
// find the days with a long enough opening
schedule.filter(({ s }) => s >= duration)
// and turn them back into an object
.reduce((s, { d, h, m }) => {
const day = s[days[d]] || (s[days[d]] = {});
const hour = day[h] || (day[h] = [])
hour.push(m)
return s
}, {})
}
const openings = {
"day 1": {
"10": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 54, 55, 56, 57, 58, 59],
"11": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59],
"12": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
"14": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
"15": [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
},
"day 2": {
"22": [26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],
"23": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 56, 57, 58, 59]
},
"day 3": {
"00": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
},
"day 4": {
"13": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
}
console.log(
schedule(openings)(20)
)
第二版
此版本可能不是首选。可能更好的方法是从上述代码中提取一些有用的函数,并根据它们进行重构。但是此版本至少没有丑陋的变异,也没有在某些默认参数之外的赋值:
const schedule = (
openings,
days = Object.keys(openings),
schedule = Object.values(openings)
.flatMap((hs, d) =>
Object.entries(hs).flatMap(([h, ms]) =>
ms.map(m => ({ h, d, m, t: d * 60 * 24 + h * 60 + m }))
)
)
.reverse()
.reduce(
({ ms, streak, prev }, { t, ...rest }) =>
t === prev - 1
? { ms: [...ms, { ...rest, t, s: streak + 1 }], streak: streak + 1, prev: t }
: { ms: [...ms, { ...rest, t, s: 1 }], streak: 1, prev: t },
{ ms: [], streak: 1, prev: -1 }
)
.ms
.reverse()
) => (duration) => schedule
.filter(({ s }) => s >= duration)
.reduce((s, { d, h, m }) => ({
...s,
[days[d]]: ({
...s[days[d]],
[h]: [...((s[days[d]] || {})[h] || []), m]
})
}), {})
const openings = {
"day 1": {
"10": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 54, 55, 56, 57, 58, 59],
"11": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59],
"12": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
"14": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
"15": [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
},
"day 2": {
"22": [26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],
"23": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 56, 57, 58, 59]
},
"day 3": {
"00": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
},
"day 4": {
"13": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
}
console.log(
schedule(openings)(20)
)