我想说我想要生成1到100之间的随机数,但我不想包括42.如果不重复随机方法,我将如何做到这一点,直到它不是42。 / p>
答案 0 :(得分:8)
var nums = [Int](1...100)
nums.removeAtIndex(42)
let random = Int(arc4random_uniform(UInt32(nums.count)))
print(nums[random])
当您想要排除多于1个值时,Range
的此扩展名确实提供了解决方案。
extension Range where Element: Hashable {
func random(without excluded:[Element]) -> Element {
let valid = Set(self).subtract(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个排除值不超过n个。
答案 1 :(得分:4)
appzYourLife有一些很棒的通用解决方案,但我希望以轻量级的方式解决具体问题。
这两种方法的工作方式大致相同:将范围缩小到随机数生成器以删除不可能的答案(99个答案而不是100个答案),然后映射结果,使其不是非法值。 / p>
这两种方法都没有增加结果相对于另一种结果的可能性。也就是说,假设您的随机数函数是完全随机的,结果仍然是随机的(例如,相对于5,没有2倍的概率为43)。
获取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,则加一个。 / p>
另一个简单的方法是从1到99得到一个数字。如果它与你试图避免的数字完全相同,那就改为100。
func approach2()->Int {
var number = Int(arc4random_uniform(99)+1)
if number == 42 {
number = 100
}
return number
}
使用这个算法并将范围缩小到1-5(同时避免3),我们得到了这些可能的结果: