2

ForwardIndexTypeinに適合性を追加してNSDateを作成できるようにしようとしています。そのためにはfromRange<NSDate>を実装する必要があります。public func successor() -> Self_Incrementable

私の実装は非常に単純で、別の日付に続く日付がちょうど 1 秒後の日付であることを示すことを目的としていますが、それはここで求められていることではありません。

extension NSDate: ForwardIndexType {
    public func successor() -> Self {
        return NSDate(timeInterval: 1, sinceDate: self) 
    }
}

私が得ているエラーは

NSDateタイプ ' ' の戻り式を戻りタイプ ' ' にSelf変換できません

as Selforを追加しようとしましたが、その場合 からへの変換は常に成功するas! Selfため、コンパイラは許可しません。で置き換えてもうまくいきません。NSDateSelfSelfNSDate

どうすれば正しい方法で行うことができますか?

4

2 に答える 2

2

いくつかのコメントが言っているように、可能であってもこれを行うべきではありません。NSDate論理的な「次」はありません。発明には副作用のリスクがあります。public 型の拡張はグローバルです。「次の日付は次の秒です」と言い、別の内線番号が「次の日付は次の日です」と言ったらどうなりますか? どちらも同じように合理的です (そして同じように正しくありません)。他の人が追加した場合に異なる意味で衝突する可能性がある拡張機能を追加しないでください。

あなたの目標は次のとおりです。

特定の間隔で n 個のランダムな日付のセットを作成したいと考えています。範囲をシャッフルして最初の n 個の値を選択したかった

それはまったく問題ありません。まず、あなたが言うように、「一定の間隔で」欲しいです。優秀な。それはClosedInterval<NSDate>です。それを得るには、NSDateComparable でなければなりません。その拡張機能を追加しても問題はありません。合理的に実装した人は、この方法で実装する必要があります。

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その場合、シャッフルははるかに効率的です。

于 2016-01-06T18:38:06.440 に答える
0

これを試して、に変更Selfし、プロトコルNSDateを削除しますForwardIndexType

    extension NSDate: _Incrementable {
    public func successor() -> Self {
        return self.dynamicType.init(timeInterval: 1, sinceDate: self)
    }
}

次のようなコードで使用します。

var date = NSDate()
date = date.successor()

let newDate = date.successor()

ForwardIndexTypeプロトコルには、のようなメソッドがあり、メソッドをadvancedBy:実装distanceTo:していますがsuccessor、プロトコルを実装するだけです_Incrementable。これは機能します。

于 2016-01-06T12:56:32.603 に答える