Python是否可以生成排除一组数字的随机数,而不使用递归?

Python是否可以生成排除一组数字的随机数,而不使用递归?,python,recursion,random,range,Python,Recursion,Random,Range,我仔细看了一下(我可能误解了),但我没有发现有一种方法可以不用调用递归函数就可以做到这一点(请看下面)。 我想做的是生成一个随机值,排除中间值。< /P> 换句话说, 让我们想象一下,我希望X是一个不在 范围(a-b,a+b) 我可以在第一次通过时这样做吗, 或 1.我是否必须不断生成一个数字, 2.检查是否在范围(), 3.洗漱 至于我为什么不想写递归函数, 1.“感觉上”我不应该这样做 2.我这样做的结果可能会非常大, ... 我听说堆栈溢出很糟糕,我可能只是在这样做时过于谨慎了 我确信有一

我仔细看了一下(我可能误解了),但我没有发现有一种方法可以不用调用递归函数就可以做到这一点(请看下面)。
我想做的是生成一个随机值,排除中间值。< /P> 换句话说,
让我们想象一下,我希望
X
是一个不在
范围(a-b,a+b)

我可以在第一次通过时这样做吗,

1.我是否必须不断生成一个数字,
2.检查是否在
范围()

3.洗漱

至于我为什么不想写递归函数,
1.“感觉上”我不应该这样做
2.我这样做的结果可能会非常大,
... 我听说堆栈溢出很糟糕,我可能只是在这样做时过于谨慎了


我确信有一种很好的、python式的、非递归的方法可以做到这一点。

最快的解决方案是这样的(a和b定义了排除区,c和d定义了一组好的答案,包括排除区):

使用random.choice()。 在本例中,a是下限,跳过b和c之间的范围,d是上限

import random
numbers = range(a,b) + range(c,d)
r = random.choice(numbers)

我可能误解了您的问题,但您可以实现它而无需递归

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

rand([1,3,9])
不过,在找到新的结果之前,您仍在循环搜索结果。

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

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

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)

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

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

生成一个随机数并将其映射到所需的数字范围

如果要生成介于
1-4
7-10
之间的整数(不包括
5
6
),可以:

  • 生成范围
    1-8
  • 如果随机数大于4,则在结果中添加
    2
  • 映射为:

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

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

    李昂业的回答使递归问题变得毫无意义,但我必须指出,可以在不担心堆栈的情况下进行任何程度的递归。这叫做“尾部递归”。Python不直接支持尾部递归,因为GvR认为它不酷:

    但你可以绕过这一点:

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


    除非可能的答案集非常大,否则这将起作用,在这种情况下,它将使用太多内存并崩溃。@AndrewG:同意,如果范围大小为数百万/数十亿,这并不理想。另一方面,它简单而难忘。你的答案,虽然是一个非常好和健壮的解决方案,但可能更容易出错。如果从一开始就知道a、b、c和d是一个小集合,我会使用你的答案;如果它们依赖于输入或已知是一个大集合,我会使用我的答案。@ihavenoidia:
    range
    始终包括第一个参数,排除第二个参数。因此,在我的示例中,
    numbers
    是[a,b)+[c,d]。可能需要将其写成
    numbers=list(范围(a,b))+list(范围(c,d))
    这将在这两个范围之间得到50/50的分布,不管它们相对而言有多大。嗯,在代码的最后一部分中一定有逻辑错误——现在尝试调试它……哦。它应该是offset=b-a。编辑。它也应该是result>=a。好了,应该是这样的。+1用于很好的解释——这是我想说的是什么,但我发现仅仅用代码无法解释。@AndrewG:谢谢。:)用几张图片就可以更好地解释,但今晚我打开Visio的激活能量有点高。;)非常感谢你,它的执行非常直接,并激励读者在而不是简单地发布代码并说“来,运行这个。”最后,我使用了Junuxx的解决方案,但我也欣赏这个答案的优雅。作为一个编程新手,这完全是我需要阅读的内容。谢谢!我不一定对递归过敏,说实话,我没有意识到,就连Python的BDFL也普遍对它表示蔑视;我只是有一个g但是我觉得我不需要在这个特定的项目中使用它。我不会排除在未来的努力中使用它。嘿,如果我的答案有用,请投票吧!我需要声誉。我以为我有。我的错误:)
    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
    
    Random number:    1  2  3  4  5  6  7  8
    Result:           1  2  3  4  7  8  9 10