LoginSignup
5
6

More than 5 years have passed since last update.

Range<Int> に distance 作って Int に指定範囲で乱数を作成させる extension

Last updated at Posted at 2016-03-30

まあよくありますよね皆さんも多分、例えば「0 から 256 までの乱数を作りたい」とかいう要望。

一応公式で教えてるやり方ですと arc4random_uniform(_: UInt32) と言う方法を使えとのことですが毎回毎回これやるのだるいじゃん?だってこいつだけ基本欲しいの Int 型だけどこいつだけ引数も戻り値も UInt32 じゃん?毎回毎回こいつのために型変換するの面倒いしそれにこれは 0 から uniform される数字までの値しか生成されないから逆に言うと 0 からでないランダム数が欲しいときだとさらに面倒い記述が求められるから超絶にだるい。というわけで extension で楽に作る方法を実装してみます:

//普通に distanceTo を使うからこの方法やめる 
//extension Range where Element: IntegerType {
extension Range {

    //普通に distanceTo を使うからこの方法やめる 
    //var distance: Element {
    //  return self.endIndex - self.startIndex
    //}

    var distance: Element.Distance {
        return self.startIndex.distanceTo(self.endIndex)
    }

}

extension Int {

    static var random = {(range: Range<Int>) -> Int in
        let distance = {(distance: Int) -> UInt32 in
            guard distance <= Int(UInt32.max) else {
                return UInt32.max
            }
            return UInt32(distance)
        }(range.distance)
        let randomUInt = arc4random_uniform(distance)
        return Int(randomUInt) + range.startIndex
    }

}


let a = Int.random(-127 ..< 128)
let b = Int.random(-127 ..< 128)

説明は…要りますかね?まあ分からないことあったらコメントで教えてください

とりあえず一つだけ多分ちょっとわからない人が多そうなのは extension Range where Element: IntergerType のところかな?ここは要するに Range の要素の型を IntegerType に限定するジェネリックスエクステンションです。本当なら別に限定する必要はないはずだったんだけどまさか実は Swift では - って演算子はジェネリックス対応ではなかったとは…

そして使い方も上記のコードで分かるとおり Int.random(範囲) で作れば OK です。上記のサンプルコードだと ab-127 ..< 128 までの範囲の乱数を二つ作ってることになります。Range 型なので非常に簡単に範囲指定ができちゃうからソースコードも結構読みやすいではないかと。

ただ当然ですが一つ気をつけないといけないのは Range<Int>distance プロパティーは endIndex - startIndex で作ってるので、例えば Int.min ..< Int.maxRangedistance を求めるとオーバーフローでクラッシュします。

5
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6