Swift 遍历日期间隔数组
Swift Iterate through array of date intervals
在我的 iOS 应用程序中,我有一个事件列表,每个事件都有开始和结束日期。我的目标是弄清楚哪些事件相互重叠 - 也就是说,如果事件 1 开始于 10 月 6 日星期一@2:30 下午并结束于 5:30 下午,而事件 4 开始于 10 月 6 日星期一@3:30下午。我需要知道这两个事件重叠。
因此,当从网络下载数据时,我创建了一个 [DateInterval]
的数组,每个 EventObjects
的开始日期和结束日期分别为。
我的问题是,遍历 eventObjects 数组然后检查开始日期是否与 [DateInterval]
日期相交的最佳方法是什么?
提前致谢
编辑
这是一个示例代码..
func sortArray (){
for object in sortedEventObjectArray {
let hasConflics = zip(datesReversed, datesReversed.dropFirst()).contains(where: { [=11=].end > .start })
if hasConflics == true {
print("conflict")
} else {
print("none")
}
}
}
[sortedEventObjectArray] is an event object which contains details like the start date and end date of event - this is what i used to populate the datesReserved array of Date Intervals
[datesReversed] is an array of DateIntervals - it looks like this
[2018-11-01 06:00:00 +0000 to 2018-11-01 09:30:00 +0000, 2018-11-01 18:00:00 +0000 to 2018-11-01 19:33:00 +0000, 2018-11-01 19:33:00 +0000 to 2018-11-01 23:00:00 +0000, 2018-11-03 18:14:00 +0000 to 2018-11-03 21:44:00 +0000, 2018-11-03 18:14:00 +0000 to 2018-11-03 21:44:00 +0000, 2018-11-06 12:00:00 +0000 to 2018-11-06 13:26:00 +0000, 2018-11-06 13:27:00 +0000 to 2018-11-06 14:00:00 +0000, 2018-11-06 17:00:00 +0000 to 2018-11-06 22:00:00 +0000, 2018-11-06 18:00:00 +0000 to 2018-11-06 21:00:00 +0000, 2018-11-07 12:00:00 +0000 to 2018-11-07 14:30:00 +0000, 2018-11-07 18:30:00 +0000 to 2018-11-07 23:00:00 +0000, 2018-11-08 11:30:00 +0000 to 2018-11-08 12:59:00 +0000, 2018-11-08 12:56:00 +0000 to 2018-11-08 13:30:00 +0000, 2018-11-08 19:30:00 +0000 to 2018-11-08 22:30:00 +0000, 2018-11-09 12:30:00 +0000 to 2018-11-09 14:30:00 +0000, 2018-11-09 15:00:00 +0000 to 2018-11-09 16:00:00 +0000, 2018-11-09 16:30:00 +0000 to 2018-11-09 21:00:00 +0000, 2018-11-09 20:00:00 +0000 to 2018-11-09 21:30:00 +0000, 2018-11-10 12:30:00 +0000 to 2018-11-10 20:30:00 +0000, 2018-11-10 13:45:00 +0000 to 2018-11-10 14:30:00 +0000, 2018-11-10 18:00:00 +0000 to 2018-11-10 19:00:00 +0000]
我得到的输出是 - (这是错误的,因为很明显其中一些日期没有安排冲突)
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
一个有效的解决方案是通过首先增加开始日期来排序事件。然后你只需要将每个事件与以后开始的事件进行比较。
如果模型对象是
struct Event {
let title: String
let duration: DateInterval
}
那么它可能看起来像这样(未经测试):
var events: [Event] = ...
events.sort(by: { [=11=].duration.start < .duration.start })
for i in events.indices.dropLast() {
for j in (i + 1)..<events.endIndex {
if events[i].duration.end > events[j].duration.start {
print(events[i].title, "overlaps with", events[j].title)
} else {
break
}
}
}
请注意,如果发现非重叠事件,则内部循环可以终止,因为事件是按开始日期递增排序的。
如果您只需要知道 任何 事件是否重叠,那么将每个事件持续时间与以下事件的持续时间进行比较就足够了:
var events: [Event] = ...
events.sort(by: { [=12=].duration.start < .duration.start })
var hasConflicts = false
for i in events.indices.dropLast() {
if events[i].duration.end > events[i+1].duration.start {
hasConflics = true
break
}
}
使用zip
此代码可以缩短为
var events: [Event] = ...
events.sort(by: { [=13=].duration.start < .duration.start })
let hasConflics = zip(events, events.dropFirst())
.contains(where: { [=13=].duration.end > .duration.start })
您可以扩展 DateInterval
来检查重叠事件。
我们可以将其分解为 3 个验证来检查:
(假设事件 eventA 已经设置并且你用 eventB 检查它)
- 检查事件 B 是否在事件 B 之后开始并在事件 A 结束之前结束。
- 检查事件 B 是否在事件 A 开始之后和事件 A 结束之前结束。
- 检查事件 B 是否在事件 A 开始之前开始并在事件 A 结束之后结束。
- 正在检查 eventA 和 eventB 是否同时开始。
鉴于此,我认为这个解决方案可以完成工作:
extension DateInterval {
func isOverlaps(with di: DateInterval) -> Bool {
let answer =
checkIfDItartAtTheSameTime(dateInterval: di) ||
checkIfDIIsBetween(date: di.start) ||
checkIfDIIsBetween(date: di.end) ||
checkIfDIStartsBeforeAndEndsAfter(dateInterval: di)
return answer
}
private func checkIfDIIsBetween(date: Date) -> Bool {
return date > start && date < end || date == start
}
private func checkIfDIStartsBeforeAndEndsAfter(dateInterval: DateInterval) -> Bool {
return dateInterval.start < start && dateInterval.end > end
}
private func checkIfDItartAtTheSameTime(dateInterval: DateInterval) -> Bool {
return dateInterval.start == start
}
}
现在,在你的迭代中,你可以检查:
[intervalA, intervalB].forEach { di in
if di.isOverlaps(with: someOtherDateInterval) {
print("conflict")
} else {
print("Not Conflicting!")
}
}
希望对您有所帮助! :)
在我的 iOS 应用程序中,我有一个事件列表,每个事件都有开始和结束日期。我的目标是弄清楚哪些事件相互重叠 - 也就是说,如果事件 1 开始于 10 月 6 日星期一@2:30 下午并结束于 5:30 下午,而事件 4 开始于 10 月 6 日星期一@3:30下午。我需要知道这两个事件重叠。
因此,当从网络下载数据时,我创建了一个 [DateInterval]
的数组,每个 EventObjects
的开始日期和结束日期分别为。
我的问题是,遍历 eventObjects 数组然后检查开始日期是否与 [DateInterval]
日期相交的最佳方法是什么?
提前致谢
编辑
这是一个示例代码..
func sortArray (){
for object in sortedEventObjectArray {
let hasConflics = zip(datesReversed, datesReversed.dropFirst()).contains(where: { [=11=].end > .start })
if hasConflics == true {
print("conflict")
} else {
print("none")
}
}
}
[sortedEventObjectArray] is an event object which contains details like the start date and end date of event - this is what i used to populate the datesReserved array of Date Intervals
[datesReversed] is an array of DateIntervals - it looks like this
[2018-11-01 06:00:00 +0000 to 2018-11-01 09:30:00 +0000, 2018-11-01 18:00:00 +0000 to 2018-11-01 19:33:00 +0000, 2018-11-01 19:33:00 +0000 to 2018-11-01 23:00:00 +0000, 2018-11-03 18:14:00 +0000 to 2018-11-03 21:44:00 +0000, 2018-11-03 18:14:00 +0000 to 2018-11-03 21:44:00 +0000, 2018-11-06 12:00:00 +0000 to 2018-11-06 13:26:00 +0000, 2018-11-06 13:27:00 +0000 to 2018-11-06 14:00:00 +0000, 2018-11-06 17:00:00 +0000 to 2018-11-06 22:00:00 +0000, 2018-11-06 18:00:00 +0000 to 2018-11-06 21:00:00 +0000, 2018-11-07 12:00:00 +0000 to 2018-11-07 14:30:00 +0000, 2018-11-07 18:30:00 +0000 to 2018-11-07 23:00:00 +0000, 2018-11-08 11:30:00 +0000 to 2018-11-08 12:59:00 +0000, 2018-11-08 12:56:00 +0000 to 2018-11-08 13:30:00 +0000, 2018-11-08 19:30:00 +0000 to 2018-11-08 22:30:00 +0000, 2018-11-09 12:30:00 +0000 to 2018-11-09 14:30:00 +0000, 2018-11-09 15:00:00 +0000 to 2018-11-09 16:00:00 +0000, 2018-11-09 16:30:00 +0000 to 2018-11-09 21:00:00 +0000, 2018-11-09 20:00:00 +0000 to 2018-11-09 21:30:00 +0000, 2018-11-10 12:30:00 +0000 to 2018-11-10 20:30:00 +0000, 2018-11-10 13:45:00 +0000 to 2018-11-10 14:30:00 +0000, 2018-11-10 18:00:00 +0000 to 2018-11-10 19:00:00 +0000]
我得到的输出是 - (这是错误的,因为很明显其中一些日期没有安排冲突)
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
一个有效的解决方案是通过首先增加开始日期来排序事件。然后你只需要将每个事件与以后开始的事件进行比较。
如果模型对象是
struct Event {
let title: String
let duration: DateInterval
}
那么它可能看起来像这样(未经测试):
var events: [Event] = ...
events.sort(by: { [=11=].duration.start < .duration.start })
for i in events.indices.dropLast() {
for j in (i + 1)..<events.endIndex {
if events[i].duration.end > events[j].duration.start {
print(events[i].title, "overlaps with", events[j].title)
} else {
break
}
}
}
请注意,如果发现非重叠事件,则内部循环可以终止,因为事件是按开始日期递增排序的。
如果您只需要知道 任何 事件是否重叠,那么将每个事件持续时间与以下事件的持续时间进行比较就足够了:
var events: [Event] = ...
events.sort(by: { [=12=].duration.start < .duration.start })
var hasConflicts = false
for i in events.indices.dropLast() {
if events[i].duration.end > events[i+1].duration.start {
hasConflics = true
break
}
}
使用zip
此代码可以缩短为
var events: [Event] = ...
events.sort(by: { [=13=].duration.start < .duration.start })
let hasConflics = zip(events, events.dropFirst())
.contains(where: { [=13=].duration.end > .duration.start })
您可以扩展 DateInterval
来检查重叠事件。
我们可以将其分解为 3 个验证来检查: (假设事件 eventA 已经设置并且你用 eventB 检查它)
- 检查事件 B 是否在事件 B 之后开始并在事件 A 结束之前结束。
- 检查事件 B 是否在事件 A 开始之后和事件 A 结束之前结束。
- 检查事件 B 是否在事件 A 开始之前开始并在事件 A 结束之后结束。
- 正在检查 eventA 和 eventB 是否同时开始。
鉴于此,我认为这个解决方案可以完成工作:
extension DateInterval {
func isOverlaps(with di: DateInterval) -> Bool {
let answer =
checkIfDItartAtTheSameTime(dateInterval: di) ||
checkIfDIIsBetween(date: di.start) ||
checkIfDIIsBetween(date: di.end) ||
checkIfDIStartsBeforeAndEndsAfter(dateInterval: di)
return answer
}
private func checkIfDIIsBetween(date: Date) -> Bool {
return date > start && date < end || date == start
}
private func checkIfDIStartsBeforeAndEndsAfter(dateInterval: DateInterval) -> Bool {
return dateInterval.start < start && dateInterval.end > end
}
private func checkIfDItartAtTheSameTime(dateInterval: DateInterval) -> Bool {
return dateInterval.start == start
}
}
现在,在你的迭代中,你可以检查:
[intervalA, intervalB].forEach { di in
if di.isOverlaps(with: someOtherDateInterval) {
print("conflict")
} else {
print("Not Conflicting!")
}
}
希望对您有所帮助! :)