Быстрая итерация по массиву интервалов дат - PullRequest
0 голосов
/ 17 октября 2019

В моем приложении для iOS у меня есть список событий, каждый из которых имеет дату начала и окончания. Моя цель - выяснить, какие события перекрывают друг друга, то есть если событие1 начинается понедельник, 6 октября, 14:30 и заканчивается в 17:30, а событие 4 начинается понедельник, 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

Ответы [ 2 ]

1 голос
/ 17 октября 2019

Эффективным решением является сортировка событий, сначала увеличив дату начала. Тогда вам нужно только сравнить каждое событие с тем, которое начинается позже.

Если объект модели

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 })
0 голосов
/ 17 октября 2019

Вы можете расширить DateInterval, чтобы проверить наличие совпадений.

Мы можем разбить его на 3 проверки для проверки: (предположим, что событие eventA уже установлено, и вы проверяете с помощью eventB)

  1. Проверка, начинается ли eventB после начала и окончания eventBдо окончания eventA.
  2. Проверка, заканчивается ли eventB после начала eventA и до окончания eventA.
  3. Проверка, начинается ли eventB до начала eventA и заканчивается после окончания eventA.
  4. Проверка, если eventAи событие 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!")
      }
}

Надеюсь, это поможет! :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...