正如几条评论所说,即使可能,您也不应该这样做。NSDate
没有合乎逻辑的“下一个”。发明一种可能会产生副作用。公共类型的扩展是全局的。如果您说“下一个日期是下一秒”而另一个扩展名说“下一个日期是第二天”会发生什么?两者都同样合理(同样不正确)。如果其他人也这样做,切勿添加可能与不同含义发生冲突的扩展名。
你说你的目标是:
我想在给定的时间间隔内创建一组 n 个随机日期。我想打乱一个范围并选择前 n 个值
这完全没有问题。首先,正如您所说,您想要“在给定的时间间隔内”。出色的。那是一个ClosedInterval<NSDate>
。要做到这一点,NSDate
必须是可比的。添加该扩展名没有任何问题。任何合理实施它的人都必须以这种方式实施。
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
现在您想将其转换为整数秒范围,而不是日期范围。然后打乱该范围内的元素,提取第一个n
值,并将它们映射回日期。我们假设您已经拥有 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)) }
}
a 的权衡是,如果与间隔中的秒数具有相似的量级,则Set
此方法非常慢。n
在这种情况下,洗牌效率更高。