从 DateInterval 数组中排除 DateInterval 数组
exclude Array of DateInterval from Array of DateInterval
我想从 DateInterval
数组中排除 DateInterval
数组。这是我的代码,但我认为它不会有帮助..它有时会进入无限循环,我无法解决它。
extension DateInterval {
static func exclude(_ excludedIntervals: [DateInterval], from periods: [DateInterval]) -> [DateInterval] {
if excludedIntervals.isEmpty { return periods }
var resultSlots: [DateInterval] = []
for period in periods {
let results = period.exclude(excludedIntervals)
resultSlots.append(contentsOf: results)
}
return resultSlots
}
func exclude(_ execludedIntervals: [DateInterval]) -> [DateInterval] {
if execludedIntervals.isEmpty { return [self] }
var sortedExecludedIntervals = execludedIntervals.sorted()
var resultSlots: [DateInterval] = []
var execludedInterval = sortedExecludedIntervals.removeFirst()
// remove execludedIntervals from self
if let intersection = self.intersection(with: execludedInterval) {
if self.start == intersection.start && self.end > intersection.end {
let newSlot = DateInterval(start: intersection.end, end: self.end)
resultSlots.append(contentsOf: newSlot.exclude(sortedExecludedIntervals))
} else if self.start < intersection.start && self.end == intersection.end {
let newSlot = DateInterval(start: self.start, end: intersection.start)
resultSlots.append(contentsOf: newSlot.exclude(sortedExecludedIntervals))
} else if self.start < intersection.start && self.end > intersection.end {
let preSlot = DateInterval(start: self.start, end: intersection.start)
resultSlots.append(contentsOf: preSlot.exclude(sortedExecludedIntervals))
let postSlot = DateInterval(start: intersection.end, end: self.end)
resultSlots.append(contentsOf: postSlot.exclude(sortedExecludedIntervals))
} else {
// start = start && end = end
resultSlots = []
return resultSlots
}
}
return resultSlots
}
}
例如,我想从中午 12 点到下午 6 点的时间间隔中排除下午 1 点到下午 3 点和下午 5 点到下午 6 点的时间间隔。该函数应 return 中午 12 点 - 下午 1 点和下午 3 点 - 下午 5 点。
几个想法:
如果我想要一个方法对 DateInterval
的数组进行操作,我建议将其放在 Array
(或 Sequence
)扩展中,限于 DateInterval
类型,而不是 DateInterval
:
上的 static
方法
extension Array where Element == DateInterval {
func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] { ... }
}
当考虑从另一个中排除一个 DateInterval
时,有很多不同的场景:
- 您可以从间隔中间排除一些小的 window;
- 您可以在间隔开始时排除一部分;
- 您可以排除间隔末尾的一部分;和
- 您可以排除整个区间。
在我看来,考虑所有这些场景太混乱了,所以我决定稍微简化一下并决定:
- 排除区域与当前区间相交的确切位置(
DateInterval
为我们提供了一个很好的方法);
- 如果我从日期间隔中“剪掉”那个交叉点,我可能会得到两个间隔,一个
before
间隔和一个 after
间隔(例如,如果我剪掉 2pm-3pm中午至下午 6 点,before
间隔时间为中午至下午 2 点,after
间隔时间为下午 3 点至下午 6 点);
- 算法然后提炼为“如果区间与排除区域相交,则将原始区间替换为另外两个区间,一个在前,一个在后”;和
- 考虑到我正在改变结果区间的原始数组,我建议使用嵌套循环,外循环是要排除的区间,内循环是结果区间,因为它在变异,我将使用
while
语句进行迭代,手动检查和调整当前的 index
。
产生:
extension Array where Element == DateInterval {
func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] {
var results: [DateInterval] = self
for excludedInterval in excludedIntervals {
var index = results.startIndex
while index < results.endIndex {
let interval = results[index]
if let intersection = interval.intersection(with: excludedInterval) {
var before: DateInterval?
var after: DateInterval?
if intersection.start > interval.start {
before = DateInterval(start: interval.start, end: intersection.start)
}
if intersection.end < interval.end {
after = DateInterval(start: intersection.end, end: interval.end)
}
let replacements = [before, after].compactMap { [=11=] }
results.replaceSubrange(index...index, with: replacements)
index += replacements.count
} else {
index += 1
}
}
}
return results
}
}
然后我们可以将应用于单个 DateInterval
的排除视为仅包含一项的数组的特例:
extension DateInterval {
func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] {
return [self].exclude(excludedIntervals)
}
}
所以:
let formatter = ISO8601DateFormatter()
let start = formatter.date(from: "2019-02-09T12:00:00Z")!
let end = formatter.date(from: "2019-02-09T18:00:00Z")!
let exclude1Start = formatter.date(from: "2019-02-09T13:00:00Z")!
let exclude1End = formatter.date(from: "2019-02-09T14:00:00Z")!
let exclude2Start = formatter.date(from: "2019-02-09T16:00:00Z")!
let exclude2End = formatter.date(from: "2019-02-09T17:00:00Z")!
let intervals = DateInterval(start: start, end: end)
.exclude([
DateInterval(start: exclude1Start, end: exclude1End),
DateInterval(start: exclude2Start, end: exclude2End)
])
print(intervals)
将产生:
[
2019-02-09 12:00:00 +0000 to 2019-02-09 13:00:00 +0000,
2019-02-09 14:00:00 +0000 to 2019-02-09 16:00:00 +0000,
2019-02-09 17:00:00 +0000 to 2019-02-09 18:00:00 +0000
]
我想从 DateInterval
数组中排除 DateInterval
数组。这是我的代码,但我认为它不会有帮助..它有时会进入无限循环,我无法解决它。
extension DateInterval {
static func exclude(_ excludedIntervals: [DateInterval], from periods: [DateInterval]) -> [DateInterval] {
if excludedIntervals.isEmpty { return periods }
var resultSlots: [DateInterval] = []
for period in periods {
let results = period.exclude(excludedIntervals)
resultSlots.append(contentsOf: results)
}
return resultSlots
}
func exclude(_ execludedIntervals: [DateInterval]) -> [DateInterval] {
if execludedIntervals.isEmpty { return [self] }
var sortedExecludedIntervals = execludedIntervals.sorted()
var resultSlots: [DateInterval] = []
var execludedInterval = sortedExecludedIntervals.removeFirst()
// remove execludedIntervals from self
if let intersection = self.intersection(with: execludedInterval) {
if self.start == intersection.start && self.end > intersection.end {
let newSlot = DateInterval(start: intersection.end, end: self.end)
resultSlots.append(contentsOf: newSlot.exclude(sortedExecludedIntervals))
} else if self.start < intersection.start && self.end == intersection.end {
let newSlot = DateInterval(start: self.start, end: intersection.start)
resultSlots.append(contentsOf: newSlot.exclude(sortedExecludedIntervals))
} else if self.start < intersection.start && self.end > intersection.end {
let preSlot = DateInterval(start: self.start, end: intersection.start)
resultSlots.append(contentsOf: preSlot.exclude(sortedExecludedIntervals))
let postSlot = DateInterval(start: intersection.end, end: self.end)
resultSlots.append(contentsOf: postSlot.exclude(sortedExecludedIntervals))
} else {
// start = start && end = end
resultSlots = []
return resultSlots
}
}
return resultSlots
}
}
例如,我想从中午 12 点到下午 6 点的时间间隔中排除下午 1 点到下午 3 点和下午 5 点到下午 6 点的时间间隔。该函数应 return 中午 12 点 - 下午 1 点和下午 3 点 - 下午 5 点。
几个想法:
如果我想要一个方法对
上的DateInterval
的数组进行操作,我建议将其放在Array
(或Sequence
)扩展中,限于DateInterval
类型,而不是DateInterval
:static
方法extension Array where Element == DateInterval { func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] { ... } }
当考虑从另一个中排除一个
DateInterval
时,有很多不同的场景:- 您可以从间隔中间排除一些小的 window;
- 您可以在间隔开始时排除一部分;
- 您可以排除间隔末尾的一部分;和
- 您可以排除整个区间。
在我看来,考虑所有这些场景太混乱了,所以我决定稍微简化一下并决定:
- 排除区域与当前区间相交的确切位置(
DateInterval
为我们提供了一个很好的方法); - 如果我从日期间隔中“剪掉”那个交叉点,我可能会得到两个间隔,一个
before
间隔和一个after
间隔(例如,如果我剪掉 2pm-3pm中午至下午 6 点,before
间隔时间为中午至下午 2 点,after
间隔时间为下午 3 点至下午 6 点); - 算法然后提炼为“如果区间与排除区域相交,则将原始区间替换为另外两个区间,一个在前,一个在后”;和
- 考虑到我正在改变结果区间的原始数组,我建议使用嵌套循环,外循环是要排除的区间,内循环是结果区间,因为它在变异,我将使用
while
语句进行迭代,手动检查和调整当前的index
。
产生:
extension Array where Element == DateInterval {
func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] {
var results: [DateInterval] = self
for excludedInterval in excludedIntervals {
var index = results.startIndex
while index < results.endIndex {
let interval = results[index]
if let intersection = interval.intersection(with: excludedInterval) {
var before: DateInterval?
var after: DateInterval?
if intersection.start > interval.start {
before = DateInterval(start: interval.start, end: intersection.start)
}
if intersection.end < interval.end {
after = DateInterval(start: intersection.end, end: interval.end)
}
let replacements = [before, after].compactMap { [=11=] }
results.replaceSubrange(index...index, with: replacements)
index += replacements.count
} else {
index += 1
}
}
}
return results
}
}
然后我们可以将应用于单个 DateInterval
的排除视为仅包含一项的数组的特例:
extension DateInterval {
func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] {
return [self].exclude(excludedIntervals)
}
}
所以:
let formatter = ISO8601DateFormatter()
let start = formatter.date(from: "2019-02-09T12:00:00Z")!
let end = formatter.date(from: "2019-02-09T18:00:00Z")!
let exclude1Start = formatter.date(from: "2019-02-09T13:00:00Z")!
let exclude1End = formatter.date(from: "2019-02-09T14:00:00Z")!
let exclude2Start = formatter.date(from: "2019-02-09T16:00:00Z")!
let exclude2End = formatter.date(from: "2019-02-09T17:00:00Z")!
let intervals = DateInterval(start: start, end: end)
.exclude([
DateInterval(start: exclude1Start, end: exclude1End),
DateInterval(start: exclude2Start, end: exclude2End)
])
print(intervals)
将产生:
[
2019-02-09 12:00:00 +0000 to 2019-02-09 13:00:00 +0000,
2019-02-09 14:00:00 +0000 to 2019-02-09 16:00:00 +0000,
2019-02-09 17:00:00 +0000 to 2019-02-09 18:00:00 +0000
]