快速遍历日期间隔数组

时间:2019-10-17 04:42:56

标签: ios arrays swift dateinterval

在我的iOS应用中,我有一个事件列表,每个事件都有开始和结束日期。我的目标是弄清楚哪些事件相互重叠-意思是,如果event1在10月6日星期一2:30 pm开始并在5:30 pm结束,而event4在10月6日星期一3:30 pm 3点开始了。我需要知道这两个事件是重叠的。

因此,当从网络上下载数据时,我创建了一个[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

2 个答案:

答案 0 :(得分:1)

一种有效的解决方案是通过先增加开始日期来排序事件。然后,您只需将每个事件与稍后开始的事件进行比较。

如果模型对象是

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

答案 1 :(得分:0)

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

我们可以将其细分为3个验证以进行检查: (假设事件eventA已经设置,并且您要针对它检查eventB)

  1. 检查eventB是否在eventB之后开始,是否在eventA结束之前结束。
  2. 检查eventB在eventA开始之后和eventA结束之前是否结束。
  3. 检查eventB是在eventA开始之前开始还是在eventA结束之后结束。
  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!")
      }
}

希望有帮助! :)