正如幾位評論所說,即使可能,你也不應該這樣做。 NSDate
沒有邏輯「下一個」。創造一個風險的副作用。公共類型的擴展是全球性的。如果你說「下一個日期是下一秒」而另一個擴展說「下一個日期是第二天?」會發生什麼?兩者同樣合理(同樣不正確)。如果其他人也這樣做,請勿添加可能與不同含義相沖突的擴展名。
你說你的目標是:
I want to create a set of n random dates in a given interval. I wanted to shuffle a range and select the first n values
這是一點問題都沒有。首先,如你所說,你希望「在給定的時間間隔內」。優秀。這是一個ClosedInterval<NSDate>
。爲了得到那個,NSDate
必須是可比較的。添加該擴展沒有任何問題。任何合理實施它的人都必須以這種方式實施。
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
現在您要將其轉換爲積分秒範圍,而不是日期範圍。然後將該範圍內的元素進行混洗,取出第一個值,並將其映射回日期。我們假設你已經有Nate Cook的shuffle code。
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)) }
}
一個Set
的代價是,這種做法是非常緩慢的,如果n
類似幅度的要數在間隔內秒數。在那種情況下,洗牌效率會更高。
接班人會是什麼:總是第二?或一天?毫秒?您只應將具有自然後繼的構造的後繼定義爲整數。 1之後是2.即對於不存在這樣的自然後繼者的浮體。此外,對於某個時間點,沒有天然的繼任者,並且NSDate正在代表這樣一個觀點,因此它不應該有一個好的繼任者。 – vikingosegundo
正如我在我的問題中所述,即使我認爲這是一個非常有效的討論,我會認爲它應該總是一秒鐘。 – fpg1503
但爲什麼它需要成爲後繼方法。只需創建'advanceByOneSecond()'或更好'advanceBy(_time,inUnit:NSCalendarUnit)'。 – vikingosegundo