исключить массив DateInterval из массива DateInterval - PullRequest
0 голосов
/ 10 февраля 2019

Я хочу исключить массив DateInterval из массива DateInterval.Это мой код, но я не думаю, что он будет бесполезен ... иногда он идет в бесконечном цикле, и я не могу его решить.

extension DateInterval {

    static func exclude(_ excludedIntervals: [DateInterval], from periods: [DateInterval]) -> [DateInterval] {
        if excludedIntervals.isEmpty { return periods }
        var resultSlots: [DateInterval] = []

        for period in periods {
            let results = period.exclude(excludedIntervals)
            resultSlots.append(contentsOf: results)
        }

        return resultSlots
    }

    func exclude(_ execludedIntervals: [DateInterval]) -> [DateInterval] {
        if execludedIntervals.isEmpty { return [self] }
        var sortedExecludedIntervals = execludedIntervals.sorted()
        var resultSlots: [DateInterval] = []
        var execludedInterval = sortedExecludedIntervals.removeFirst()
        // remove execludedIntervals from self
        if let intersection = self.intersection(with: execludedInterval) {
            if self.start == intersection.start && self.end > intersection.end {
                let newSlot = DateInterval(start: intersection.end, end: self.end)
                resultSlots.append(contentsOf: newSlot.exclude(sortedExecludedIntervals))
            } else if self.start < intersection.start && self.end == intersection.end {
                let newSlot = DateInterval(start: self.start, end: intersection.start)
                resultSlots.append(contentsOf: newSlot.exclude(sortedExecludedIntervals))
            } else if self.start < intersection.start && self.end > intersection.end {
                let preSlot = DateInterval(start: self.start, end: intersection.start)
                resultSlots.append(contentsOf: preSlot.exclude(sortedExecludedIntervals))
                let postSlot = DateInterval(start: intersection.end, end: self.end)
                resultSlots.append(contentsOf: postSlot.exclude(sortedExecludedIntervals))
            } else {
                // start = start && end = end
                resultSlots = []
                return resultSlots
            }
        }


        return resultSlots
    } 
}

Например, я хочу исключить 13:00 -С 15:00 до 17:00 - 18:00 с 12:00 до 18:00.Функция должна возвращать 12:00 - 13:00 и 15:00 - 17:00.

1 Ответ

0 голосов
/ 10 февраля 2019

Пара мыслей:

  1. Если я хочу, чтобы метод работал с массивом DateInterval, я бы предложил поместить его в Array (или Sequence) расширение, ограниченное DateInterval типами, а не static метод для DateInterval:

    extension Array where Element == DateInterval {
        func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] { ... }
    }
    
  2. При рассмотрении вопроса об исключении DateInterval из другого, существуюттонн различных сценариев:

    • Вы можете исключить небольшое окно из середины интервала;
    • Вы можете исключить часть в начале интервала;
    • Вы можете исключить часть в конце интервала;и
    • Вы можете исключить весь интервал.

    На мой взгляд, становится слишком грязно, чтобы думать обо всех этих сценариях, поэтому я решил немного упростить это и решить:

    • Где именно исключаетсяобласть пересекается с текущим интервалом (и DateInterval предоставляет хороший способ сделать это для нас);
    • Если я «вырежу» это пересечение из интервала дат, я мог бы получить два интервала, aИнтервал before и интервал after (например, если я вырежу 14:00 - 15:00 из полудня - 6:00, интервал before будет равняться 12:00 - 14:00, а интервал after - 15:00 - 18:00);
    • Затем алгоритм переходит вниз: «Если интервал пересекается исключенной областью, замените исходный интервал двумя другими интервалами: один до и один после»;и
    • Учитывая, что я изменяю исходный массив результирующих интервалов, я бы предложил вложенные циклы, причем внешний цикл - это интервалы, которые должны быть исключены, а внутренний цикл - результирующие интервалы, которые, поскольку он мутируетЯ проведу итерацию с помощью оператора while, проверяя и корректируя текущий index вручную.

То есть:

extension Array where Element == DateInterval {
    func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] {
        var results: [DateInterval] = self

        for excludedInterval in excludedIntervals {
            var index = results.startIndex
            while index < results.endIndex {
                let interval = results[index]
                if let intersection = interval.intersection(with: excludedInterval) {
                    var before: DateInterval?
                    var after: DateInterval?

                    if intersection.start > interval.start {
                        before = DateInterval(start: interval.start, end: intersection.start)
                    }
                    if intersection.end < interval.end {
                        after = DateInterval(start: intersection.end, end: interval.end)
                    }
                    let replacements = [before, after].compactMap { $0 }
                    results.replaceSubrange(index...index, with: replacements)
                    index += replacements.count
                } else {
                    index += 1
                }
            }
        }

        return results
    }
}

Тогда мы можем рассматривать исключение, примененное к одному DateInterval, как особый случай массива с однимпункт:

extension DateInterval {
    func exclude(_ excludedIntervals: [DateInterval]) -> [DateInterval] {
        return [self].exclude(excludedIntervals)
    }
}

Итак:

let formatter = ISO8601DateFormatter()

let start = formatter.date(from: "2019-02-09T12:00:00Z")!
let end = formatter.date(from: "2019-02-09T18:00:00Z")!

let exclude1Start = formatter.date(from: "2019-02-09T13:00:00Z")!
let exclude1End = formatter.date(from: "2019-02-09T14:00:00Z")!

let exclude2Start = formatter.date(from: "2019-02-09T16:00:00Z")!
let exclude2End = formatter.date(from: "2019-02-09T17:00:00Z")!

let intervals = DateInterval(start: start, end: end)
    .exclude([
        DateInterval(start: exclude1Start, end: exclude1End),
        DateInterval(start: exclude2Start, end: exclude2End)
    ])

print(intervals)

Произведет:

[
    2019-02-09 12:00:00 +0000 to 2019-02-09 13:00:00 +0000,
    2019-02-09 14:00:00 +0000 to 2019-02-09 16:00:00 +0000,
    2019-02-09 17:00:00 +0000 to 2019-02-09 18:00:00 +0000
] 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...