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 检查它)

  1. 检查事件 B 是否在事件 B 之后开始并在事件 A 结束之前结束。
  2. 检查事件 B 是否在事件 A 开始之后和事件 A 结束之前结束。
  3. 检查事件 B 是否在事件 A 开始之前开始并在事件 A 结束之后结束。
  4. 正在检查 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!")
      }
}

希望对您有所帮助! :)