我想从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 pm到6 pm的间隔中排除1 pm- 3 pm和5 pm-6 pm的间隔。该功能应返回下午12时至下午1时及下午3时至下午5时。
发布于 2019-02-10 04:23:48
有几个想法:
DateInterval
数组进行操作,我建议将它放在Array
(或Sequence
)扩展中,限制为DateInterval
类型,而不是DateInterval
上的static
方法:
扩展数组,其中元素== DateInterval { func排除(_ excludedIntervals: DateInterval) -> DateInterval {.}DateInterval
时,有大量不同的场景:- You could exclude some small window from the middle of the interval;
- You could exclude a portion at the start of the interval;
- You could exclude a portion at the end of the interval; and
- You could exclude the whole interval.
在我看来,考虑所有这些场景都会变得过于混乱,所以我决定简化一下,并决定:
- Where exactly does the excluded region intersect with the current interval (and `DateInterval` supplies a nice method to do that for us);
- If I “cut out” that intersection from the date interval, I might end up with two intervals, a `before` interval and an `after` interval (e.g. if I cut 2pm-3pm out of noon-6pm, the `before` interval will be noon-2pm and the `after` interval will be 3pm-6pm);
- The algorithm then distills down to “if the interval is intersected by the excluded region, replace the original interval with the two other intervals, the one before and the one after”; and
- Given that I’m mutating the original array of resulting intervals, I’d suggest nested loops, with the outer loop being the intervals to be excluded and the inner loop being the resulting intervals which, because it’s mutating, I’ll iterate through using a `while` statement, manually checking and adjusting the current `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 { $0 }
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
]
https://stackoverflow.com/questions/54612795
复制相似问题