いくつかのコメントが言っているように、可能であってもこれを行うべきではありません。NSDate
論理的な「次」はありません。発明には副作用のリスクがあります。public 型の拡張はグローバルです。「次の日付は次の秒です」と言い、別の内線番号が「次の日付は次の日です」と言ったらどうなりますか? どちらも同じように合理的です (そして同じように正しくありません)。他の人が追加した場合に異なる意味で衝突する可能性がある拡張機能を追加しないでください。
あなたの目標は次のとおりです。
特定の間隔で n 個のランダムな日付のセットを作成したいと考えています。範囲をシャッフルして最初の n 個の値を選択したかった
それはまったく問題ありません。まず、あなたが言うように、「一定の間隔で」欲しいです。優秀な。それはClosedInterval<NSDate>
です。それを得るには、NSDate
Comparable でなければなりません。その拡張機能を追加しても問題はありません。合理的に実装した人は、この方法で実装する必要があります。
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
これを日付の範囲ではなく、整数の秒の範囲に変換します。次に、その範囲内の要素をシャッフルし、最初のn
値を取得して、それらを日付にマッピングします。ネイト クックのシャッフル コードを既に持っていると仮定します。
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
// For convenience we're going to assume that the range is no larger than 68 years.
// If you need ranges larger than that, it's a bit more work and probably the subject
// of a second question. (See https://stackoverflow.com/a/34388108/97337 for the basis.)
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
let offsets = (0...intervalSize).shuffle()
return Array(offsets.map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }.prefix(count))
}
また、それを使用して、...
または..<
間隔を定義することもできます。
// 100 second-interval dates from the last hour
randomDatesInInterval(NSDate(timeIntervalSinceNow: -3600)...NSDate(), count: 100)
.forEach { print($0) }
このアルゴリズムはn
、間隔の秒数よりも劇的に小さい場合、少し遅くなり、メモリを集中的に使用することに注意してください。あなたが要求した方法でそれを行うには、非常に膨大な数の配列になる可能性があるものを作成する必要があります。重複を気にしない場合は、すべてがはるかに簡単です。
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
return (1...count).map { _ in
let offset = arc4random_uniform(intervalSize)
return interval.start.dateByAddingTimeInterval(Double(offset))
}
間隔が より大幅に大きい場合n
、重複の可能性は低くなります。その巨大な初期配列を割り当てずに重複を回避したい場合は、次のことを検討してSet
ください。
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
var offsets = Set<UInt32>()
while offsets.count < count {
offsets.insert(arc4random_uniform(intervalSize))
}
return offsets.sort().map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }
}
a のトレードオフは、が間隔の秒数と同程度の大きさであるSet
場合、このアプローチが非常に遅くなることです。n
その場合、シャッフルははるかに効率的です。