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.
Updated for Swift 5.1
var nums = [Int](1...100)
nums.remove(at: 42)
let random = Int(arc4random_uniform(UInt32(nums.count)))
print(nums[random])
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.