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

Swift 如何在不使用while循环的情况下生成不包含1的随机数?,swift,arc4random,Swift,Arc4random,假设我想生成一个介于1和100之间的随机数,但我不想包含42。我如何做到这一点而不重复随机方法,直到它不是42。appzYourLife有一些伟大的通用解决方案,但我想以一种轻量级的方式解决具体问题 这两种方法的工作方式大致相同:将范围缩小到随机数生成器以删除不可能的答案(99个答案而不是100个答案),然后映射结果,使其不是非法值 这两种方法都不会增加一种结果相对于另一种结果的概率。也就是说,假设您的随机数函数是完全随机的,那么结果仍然是随机的(例如,43相对于5的概率不是2倍) 方法1:增加

假设我想生成一个介于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,则加一

  • 兰德(1..4)产生1,+0,=1
  • 兰德(1..4)产生2,+0,=2
  • 兰德(1..4)产生3,+1,=4
  • 兰德(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),我们得到以下可能结果:

  • 兰德(1..4)产生1;允许,因此结果=1
  • rand(1..4)产生2,允许,因此结果=2
  • 兰特(1..4)产生3;不允许,因此结果=5
  • rand(1..4)产生4,允许,因此结果=4
更新为Swift 5.1

不包括1个值 排除多个值 当您想要排除1个以上的值时,
范围的扩展确实提供了一个解决方案

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个。

实际上,你的值比你惊讶的另一个值要好得多,因为你的值在排除各种数量的数字时更灵活——如果有必要的话。它肯定更灵活。不过,它也要重得多,所以如果你只需要最初要求的答案,我的答案会更有效。@StevenFisher:是的,我发现你的解决方案非常优雅,我已经把它投了更高的票:)谢谢,@appzYourLife。我反对的不是你的答案。事实上,我真的很喜欢。(一些我还没有使用的Swift东西的很酷的例子。)只是我盯着上面的评论看了一个月,试图弄明白为什么它会把我的短裤捆在一起,我终于弄明白了。这里有一个权衡,不仅仅是“更好”。:)@StevenFisher:同意,我的答案确实解决了一个更一般的问题,但对于这里发布的确切问题,你的答案是非常快速和优化的。事实上,它确实需要时间和空间,而不是我所需要的时间和空间。是的,但是43不是有更多的机会发生吗?不,不是,不==。如果随机滚动是42,则结果只能是43。如果随机滚动是43,结果变成44,依此类推直到99变成100。我喜欢这里的两个答案。我从你那里学到了一些东西,@appzYourLife,因为我还不是一个真正敏捷的人
(1...100).random(without: [40,50,60])