swiftarc4random

How do I generate a random number not including one without using a while loop?


Let's say I want to generate a random number between 1 and 100, but I don't want to include 42. How would I do this without repeating the random method until it is not 42.


Solution

  • Updated for Swift 5.1

    Excluding 1 value

    var nums = [Int](1...100)
    nums.remove(at: 42)
    
    let random = Int(arc4random_uniform(UInt32(nums.count)))
    print(nums[random])
    

    Excluding multiple values

    This extension of Range does provide a solution when you want to exclude more than 1 value.

    extension ClosedRange where Element: Hashable {
        func random(without excluded:[Element]) -> Element {
            let valid = Set(self).subtracting(Set(excluded))
            let random = Int(arc4random_uniform(UInt32(valid.count)))
            return Array(valid)[random]
        }
    }
    

    Example

    (1...100).random(without: [40,50,60])
    

    I believe the computation complexity of this second solution is O(n) where n is the number of elements included in the range.

    The assumption here is the no more than n excluded values are provided by the caller.