RonH
RonH

Reputation: 514

What is the easiest way to generate random integers within a range in Swift?

The method I've devised so far is this:

func randRange (lower : Int , upper : Int) -> Int {
    let difference = upper - lower
    return Int(Float(rand())/Float(RAND_MAX) * Float(difference + 1)) + lower
}

This generates random integers between lower and upper inclusive.

Upvotes: 22

Views: 15858

Answers (4)

Bilal Saleem
Bilal Saleem

Reputation: 633

This can be done in the latest Swift version:

Int.random(in: 1...99)

The above will generate a random integer between 1 and 99 (inclusive of 99).

Upvotes: 6

lucamegh
lucamegh

Reputation: 644

If you are into extensions:

extension CountableClosedRange where Bound == Int {
    var randomValue: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

extension CountableRange where Bound == Int {
    var randomValue: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

(0...6).randomValue
(0..<7).randomValue

Upvotes: 2

Anton Tcholakov
Anton Tcholakov

Reputation: 3750

Edited to remove modulo bias per the suggestion in comments. (thanks!)

I think a neat way of doing this may be to use Swift's Range to define the bounds because then you can specify 1..100 or 1...100 (including or excluding the upper bound). The best I have come up with so far is:

import Foundation // needed for rand()

func randInRange(range: Range<Int>) -> Int {
    // arc4random_uniform(_: UInt32) returns UInt32, so it needs explicit type conversion to Int
    // note that the random number is unsigned so we don't have to worry that the modulo
    // operation can have a negative output
    return  Int(arc4random_uniform(UInt32(range.endIndex - range.startIndex))) + range.startIndex
}

// generate 10 random numbers between -1000 and 999
for _ in 0...100 {
    randInRange(-1000...1000)
}

I tried using an extension on Range but you cannot seem to extend Range< T where T: Int > specifically. It would be even better if you could get a syntax like (1..100).rand().

Upvotes: 14

Jean Le Moignan
Jean Le Moignan

Reputation: 22236

Here's a somewhat lighter version of it:

func randRange (lower: Int , upper: Int) -> Int {
    return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
}

This can be simplified even further if you decide this function works with unsigned values only:

func randRange (lower: UInt32 , upper: UInt32) -> UInt32 {
    return lower + arc4random_uniform(upper - lower + 1)
}

Or, following Anton's (+1 for you) excellent idea of using a range as parameter:

func random(range: Range<UInt32>) -> UInt32 {
    return range.startIndex + arc4random_uniform(range.endIndex - range.startIndex + 1)
}

Upvotes: 52

Related Questions