32

我查看了Python Docs(我可能误解了),但我没有看到有一种方法可以在不调用递归函数的情况下执行此操作(如下所示)。
我想做的是生成一个随机值,其中不包括中间的值。

换句话说,
假设我想X成为一个不在的随机数
range(a - b, a + b)
我可以在第一次通过时执行此操作吗,
或者
1. 我是否必须不断生成一个数字,
2. 检查是否在range()
3. 洗涤漂洗?

至于为什么我不想写一个递归函数,
1.它“感觉”我不应该这样做
2.我这样做的数字集实际上可能会非常大,并且
......我听说堆栈溢出很糟糕,我可能只是在这样做时过于谨慎。

我确信有一种很好的、​​Pythonic 的、非递归的方式来做到这一点。

4

7 回答 7

43

生成一个随机数并将其映射到您想要的数字范围内。

如果您想在1-4or之间生成一个整数7-10,不包括5and 6,您可以:

  1. 生成范围内的随机整数1-8
  2. 如果随机数大于 4,则添加2到结果中。

映射变为:

Random number:    1  2  3  4  5  6  7  8
Result:           1  2  3  4  7  8  9 10

这样做,您永远不需要“重新滚动”。上面的例子是针对整数的,但它也可以应用于浮点数。

于 2012-05-19T16:06:34.593 回答
31

使用随机选择()。在此示例中,a 是您的下限,b 和 c 之间的范围被跳过,d 是您的上限。

import random
numbers = range(a,b) + range(c,d)
r = random.choice(numbers)
于 2012-05-19T15:56:41.267 回答
9

一种可能的解决方案是将随机数移出该范围。例如

def NormalWORange(a, b, sigma):
    r = random.normalvariate(a,sigma)
    if r < a:
        return r-b
    else:
        return r+b

这将产生一个正态分布,在 (ab,a+b) 范围内有一个洞。

编辑:如果你想要整数,那么你需要做更多的工作。如果您想要 [c,ab] 或 [a+b,d] 范围内的整数,那么以下内容应该可以解决问题。

def RangeWORange(a, b, c, d):
    r = random.randrange(c,d-2*b) # 2*b because two intervals of length b to exclude
    if r >= a-b:
        return r+2*b
    else:
        return r
于 2012-05-19T16:03:47.300 回答
7

我可能误解了你的问题,但你可以在没有递归的情况下实现这个

def rand(exclude):
    r = None
    while r in exclude or r is None:
         r = random.randrange(1,10)
    return r

rand([1,3,9])

但是,您仍然会循环遍历结果,直到找到新的结果。

于 2012-05-19T15:56:48.793 回答
4

最快的解决方案是(用 a 和 b 定义禁区, c 和 d 是包括禁区在内的一组好的答案):

offset = b - a
maximum = d - offset
result = random.randrange(c, maximum)
if result >= a:
    result += offset
于 2012-05-19T15:56:12.440 回答
0

Li-aung Yip 的回答使递归问题变得毫无意义,但我必须指出,可以进行任何程度的递归而不用担心堆栈。它被称为“尾递归”。Python 不直接支持尾递归,因为 GvR 认为它不酷:

http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html

但是你可以解决这个问题:

http://paulbutler.org/archives/tail-recursion-in-python/

我觉得有趣的是,stick 认为递归“感觉不对”。在非常面向函数的语言中,例如 Scheme,递归是不可避免的。它允许您在不创建状态变量的情况下进行迭代,这是函数式编程范式严格避免的。

http://www.pling.org.uk/cs/pop.html

于 2012-05-20T19:07:30.147 回答
0

您仍然需要一些范围,即不包括中间值的最小-最大可能值。

你为什么不先随机选择你想要的范围的“一半”,然后在该范围内选择一个随机数?例如:

def rand_not_in_range(a,b):
    rangechoices = ((0,a-b-1),(a+b+1, 10000000))
    # Pick a half
    fromrange = random.choice(rangechoices)
    # return int from that range
    return random.randint(*fromrange)
于 2012-05-19T15:58:58.060 回答