如何在不使用 while 循环的情况下生成不包括一个的随机数?
How do I generate a random number not including one without using a while loop?
假设我想生成一个介于 1 和 100 之间的随机数,但我不想包括 42。如果不重复随机方法直到它不是 42,我将如何做到这一点。
appzYourLife 有一些很棒的通用解决方案,但我想以轻量级的方式解决特定问题。
这两种方法的工作方式大致相同:缩小随机数生成器的范围以删除不可能的答案(99 个答案而不是 100 个),然后映射结果,使其不是非法值。
这两种方法都没有增加一个结果相对于另一个结果的概率。也就是说,假设您的随机数函数是完全随机的,结果仍然是随机的(例如,43 相对于 5 没有 2 倍的机会)。
方法 1:加法。
从 1 到 99 中获取一个随机数。如果它大于或等于您要避免的数字,请将其加一。
func approach1()->Int {
var number = Int(arc4random_uniform(99)+1)
if number >= 42 {
number = number + 1
}
return number
}
例如,尝试从 1-5 生成一个不是 3 的随机数,取一个从 1 到 4 的随机数,如果它大于或等于 3,则加一。
- rand(1..4) 产生 1, +0, = 1
- rand(1..4) 产生 2, +0, = 2
- rand(1..4) 产生 3, +1, = 4
- rand(1..4) 产生 4, +1, = 5
方法二:回避。
另一种简单的方法是获取 1 到 99 之间的数字。如果它恰好等于您要避免的数字,请将其改为 100。
func approach2()->Int {
var number = Int(arc4random_uniform(99)+1)
if number == 42 {
number = 100
}
return number
}
使用这个算法并再次将范围缩小到 1-5(同时避免 3),我们得到这些可能的结果:
- rand(1..4) 产生 1;允许,所以 Result = 1
- rand(1..4) 产生 2,允许,所以 Result = 2
- rand(1..4) 产生 3;不允许,所以 Result = 5
- rand(1..4) 产生 4,允许,所以 Result = 4
Updated for Swift 5.1
排除 1 个值
var nums = [Int](1...100)
nums.remove(at: 42)
let random = Int(arc4random_uniform(UInt32(nums.count)))
print(nums[random])
排除多个值
当您想排除超过 1 个值时,Range
的这个扩展确实提供了一个解决方案。
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]
}
}
示例
(1...100).random(without: [40,50,60])
我相信第二个解决方案的计算复杂度是 O(n)
,其中 n 是范围中包含的元素数。
这里假设调用者提供的排除值不超过 n 个。
假设我想生成一个介于 1 和 100 之间的随机数,但我不想包括 42。如果不重复随机方法直到它不是 42,我将如何做到这一点。
appzYourLife 有一些很棒的通用解决方案,但我想以轻量级的方式解决特定问题。
这两种方法的工作方式大致相同:缩小随机数生成器的范围以删除不可能的答案(99 个答案而不是 100 个),然后映射结果,使其不是非法值。
这两种方法都没有增加一个结果相对于另一个结果的概率。也就是说,假设您的随机数函数是完全随机的,结果仍然是随机的(例如,43 相对于 5 没有 2 倍的机会)。
方法 1:加法。
从 1 到 99 中获取一个随机数。如果它大于或等于您要避免的数字,请将其加一。
func approach1()->Int {
var number = Int(arc4random_uniform(99)+1)
if number >= 42 {
number = number + 1
}
return number
}
例如,尝试从 1-5 生成一个不是 3 的随机数,取一个从 1 到 4 的随机数,如果它大于或等于 3,则加一。
- rand(1..4) 产生 1, +0, = 1
- rand(1..4) 产生 2, +0, = 2
- rand(1..4) 产生 3, +1, = 4
- rand(1..4) 产生 4, +1, = 5
方法二:回避。
另一种简单的方法是获取 1 到 99 之间的数字。如果它恰好等于您要避免的数字,请将其改为 100。
func approach2()->Int {
var number = Int(arc4random_uniform(99)+1)
if number == 42 {
number = 100
}
return number
}
使用这个算法并再次将范围缩小到 1-5(同时避免 3),我们得到这些可能的结果:
- rand(1..4) 产生 1;允许,所以 Result = 1
- rand(1..4) 产生 2,允许,所以 Result = 2
- rand(1..4) 产生 3;不允许,所以 Result = 5
- rand(1..4) 产生 4,允许,所以 Result = 4
Updated for Swift 5.1
排除 1 个值
var nums = [Int](1...100)
nums.remove(at: 42)
let random = Int(arc4random_uniform(UInt32(nums.count)))
print(nums[random])
排除多个值
当您想排除超过 1 个值时,Range
的这个扩展确实提供了一个解决方案。
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]
}
}
示例
(1...100).random(without: [40,50,60])
我相信第二个解决方案的计算复杂度是 O(n)
,其中 n 是范围中包含的元素数。
这里假设调用者提供的排除值不超过 n 个。