Search code examples
iosarraysswiftdateinterval

Swift Iterate through array of date intervals


In my iOS app i have a list of events that each have a start and end date. My goal is to figure out which events overlap each other - meaning, if event1 starts Mon, oct 6 @ 2:30 pm and ends at 5:30 pm and event4 starts Mon, oct 6 @ 3:30 pm. I need to know that those two events overlap.

So When downloading the data from the web, i create an array of [DateInterval]with each EventObjects start date and end date respectively.

My question is, what's the best way to iterate though the eventObjects array and then check if the start dates intersect with the [DateInterval] dates?

Thank you in advance

EDIT

here is an example code..

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]

The output i get is - (Which is wrong because its clear that some of those dates do not have scheduling conflicts )

conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict
conflict

Solution

  • An efficient solution is to sort the events by increasing start date first. Then you only have to compare each event with those that start later.

    If the model object is

    struct Event {
        let title: String
        let duration: DateInterval
    }
    

    then it could look like this (untested):

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

    Note hat the inner loop can terminate if a non-overlapping event is found, because the events are sorted by increasing start date.

    If you only need to know if any events overlap then it suffices to compare each event duration with the duration of the following event:

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

    Using zip this code can be shorted to

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