【问题标题】:Swift Iterate through array of date intervalsSwift遍历日期间隔数组
【发布时间】:2019-10-17 04:42:56
【问题描述】:

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

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

【问题讨论】:

  • @MartinR 你能试试我们之前谈话中这篇文章中的伪代码吗?

标签: ios arrays swift dateinterval


【解决方案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 })

【讨论】:

  • 感谢您的回复!我相信第二个将是最好的选择。我现在正在尝试实现该功能。我相信它必须在某种类型的循环中才能遍历整个数组,对吗?
  • @CodingwhileLoading: zip(events, events.dropFirst())“神奇地”遍历所有相邻数组元素对。
  • 嘿@MartinR 我在我的帖子中添加了一些示例代码。希望这可能是您可以指出我的错误的地方。谢谢
  • @CodingwhileLoading:第二种 (zip) 解决方案仅用于确定是否存在 any 冲突,在循环中这样做是没有意义的。 – 我建议尝试我的第一个解决方案。
  • 哦,我明白你的意思了!我会尝试嵌套循环,但我试图在 On2 上获得更好的性能
【解决方案2】:

您可以扩展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!")
      }
}

希望对您有所帮助! :)

【讨论】:

  • 请注意DateInterval 已经有一个intersects() 方法——无需重新发明轮子:)
猜你喜欢
  • 1970-01-01
  • 2020-01-17
  • 2011-01-05
  • 2019-03-27
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多