宽窄优行-由【嘉易行】项目成品而来
younger_times
2023-04-06 a1ae6802080a22e6e6ce6d0935e95facb1daca5c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
//  SwiftDate
//  Parse, validate, manipulate, and display dates, time and timezones in Swift
//
//  Created by Daniele Margutti
//   - Web: https://www.danielemargutti.com
//   - Twitter: https://twitter.com/danielemargutti
//   - Mail: hello@danielemargutti.com
//
//  Copyright © 2019 Daniele Margutti. Licensed under MIT License.
//
 
import Foundation
 
/// Time period groups are the final abstraction of date and time in DateTools.
/// Here, time periods are gathered and organized into something useful.
/// There are two main types of time period groups, `TimePeriodCollection` and `TimePeriodChain`.
open class TimePeriodGroup: Sequence, Equatable {
 
    /// Array of periods that define the group.
    internal var periods: [TimePeriodProtocol] = []
 
    /// The earliest beginning date of a `TimePeriod` in the group.
    /// `nil` if any `TimePeriod` in group has a nil beginning date (indefinite).
    public internal(set) var start: DateInRegion?
 
    /// The latest end date of a `TimePeriod` in the group.
    /// `nil` if any `TimePeriod` in group has a nil end date (indefinite).
    public internal(set) var end: DateInRegion?
 
    /// The total amount of time between the earliest and latest dates stored in the periods array.
    /// `nil` if any beginning or end date in any contained period is `nil`.
    public var duration: TimeInterval? {
        guard let start = start, let end = end else { return nil }
        return end.timeIntervalSince(start)
    }
 
    /// The number of periods in the periods array.
    public var count: Int {
        return periods.count
    }
 
    // MARK: - Equatable
 
    public static func == (lhs: TimePeriodGroup, rhs: TimePeriodGroup) -> Bool {
        return TimePeriodGroup.hasSameElements(array1: lhs.periods, rhs.periods)
    }
 
    // MARK: - Initializers
 
    public init(_ periods: [TimePeriodProtocol]? = nil) {
        self.periods = (periods ?? [])
    }
 
    // MARK: - Sequence Protocol
 
    public func makeIterator() -> IndexingIterator<[TimePeriodProtocol]> {
        return periods.makeIterator()
    }
 
    public func map<T>(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] {
        return try periods.map(transform)
    }
 
    public func filter(_ isIncluded: (TimePeriodProtocol) throws -> Bool) rethrows -> [TimePeriodProtocol] {
        return try periods.filter(isIncluded)
    }
 
    public func forEach(_ body: (TimePeriodProtocol) throws -> Void) rethrows {
        return try periods.forEach(body)
    }
 
    public func split(maxSplits: Int, omittingEmptySubsequences: Bool, whereSeparator isSeparator: (TimePeriodProtocol) throws -> Bool) rethrows -> [AnySequence<TimePeriodProtocol>] {
        return try periods.split(maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences, whereSeparator: isSeparator).map(AnySequence.init)
    }
 
    subscript(index: Int) -> TimePeriodProtocol {
        get {
            return periods[index]
        }
    }
 
    internal func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, TimePeriodProtocol) throws -> Result) rethrows -> Result {
        return try periods.reduce(initialResult, nextPartialResult)
    }
 
    // MARK: - Internal Helper Functions
 
    internal static func hasSameElements(array1: [TimePeriodProtocol], _ array2: [TimePeriodProtocol]) -> Bool {
        guard array1.count == array2.count else {
            return false // No need to sorting if they already have different counts
        }
 
        let compArray1: [TimePeriodProtocol] = array1.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in
            if period1.start == nil && period2.start == nil {
                return false
            } else if period1.start == nil {
                return true
            } else if period2.start == nil {
                return false
            } else {
                return period2.start! < period1.start!
            }
        }
        let compArray2: [TimePeriodProtocol] = array2.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in
            if period1.start == nil && period2.start == nil {
                return false
            } else if period1.start == nil {
                return true
            } else if period2.start == nil {
                return false
            } else {
                return period2.start! < period1.start!
            }
        }
        for x in 0..<compArray1.count {
            if !compArray1[x].equals(compArray2[x]) {
                return false
            }
        }
        return true
    }
}