快速迭代日期间隔数组



在我的iOS应用程序中,我有一个事件列表,每个事件都有开始和结束日期。我的目标是找出哪些事件相互重叠 - 这意味着,如果 event1 从 10 月 6 日星期一 @ 2:30 pm 开始,下午 5:30 结束,事件 4 从 10 月 6 日星期一 @ 3:30 pm 开始。我需要知道这两个事件是重叠的。

因此,从网络下载数据时,我创建了一个[DateInterval]数组,每个EventObjects分别是开始日期和结束日期。

我的问题是,遍历 eventObjects 数组然后检查开始日期是否与[DateInterval]日期相交的最佳方法是什么?

提前谢谢你

编辑

这是一个示例代码。

func sortArray (){
for object in sortedEventObjectArray {

let hasConflics = zip(datesReversed, datesReversed.dropFirst()).contains(where: { $0.end > $1.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: { $0.duration.start < $1.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: { $0.duration.start < $1.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: { $0.duration.start < $1.duration.start })
let hasConflics = zip(events, events.dropFirst())
.contains(where: { $0.duration.end > $1.duration.start })

您可以扩展DateInterval以检查重叠事件。

我们可以将其分解为 3 个验证来检查: (假设事件 A 已经设置,并且您根据它检查事件 B(

  1. 检查事件 B 是否在事件 B 开始之后开始,在事件 A 结束之前结束。
  2. 检查事件 B 是否在事件 A 开始之后和事件 A 结束之前结束。
  3. 检查事件 B 是否在事件 A 开始之前开始,在事件 A 结束之后结束。
  4. 如果事件 A 和事件 B 同时启动,则进行检查。

鉴于此,我认为此解决方案可以完成工作:

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!")
}
}

希望对您有所帮助! :)

最新更新