如何在不使用while循环的情况下生成不包含一个随机数的随机数?

时间:2015-12-17 20:13:38

标签: swift arc4random

我想说我想要生成1到100之间的随机数,但我不想包括42.如果不重复随机方法,我将如何做到这一点,直到它不是42。 / p>

2 个答案:

答案 0 :(得分:8)

排除1个值

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:增加。

获取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>

  • rand(1..4)产生1,+ 0,= 1
  • rand(1..4)产生2,+ 0,= 2
  • rand(1..4)产生3,+ 1,= 4
  • rand(1..4)产生4,+ 1,= 5

方法2:避免。

另一个简单的方法是从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
  • 兰德(1..4)产生3;不允许,所以Result = 5
  • rand(1..4)产生4,允许,因此Result = 4