繁体   English   中英

使用 choice() 和 randint() 从 2 个范围中获取 1 个数字

[英]Getting 1 number from 2 ranges with choice() and randint()

我有一段代码

import random as r
value = r.choice(r.randint(10, 30), r.randint(50, 100))
print (value)

为什么它给我以下错误,我应该如何解决它?

TypeError: choice() takes 2 positional arguments but 3 were given 

choice需要一系列项目可供选择,而不是可变参数。 包装 arguments 以创建一个匿名tuplelist ,它会起作用,改变:

value = r.choice(r.randint(10, 30), r.randint(50, 100))

至:

value = r.choice((r.randint(10, 30), r.randint(50, 100)))  # Tuple
value = r.choice([r.randint(10, 30), r.randint(50, 100)])  # List

random.choice接受单个序列。 对于如何生成所需数字,您有几个选择。

要修复直接错误,请将输入设为序列:

value = r.choice([r.randint(10, 30), r.randint(50, 100)])

这不是一个很好的解决方案,因为它会生成两个数字,这很浪费。 此外,生成的分布取决于范围的大小,这可能是不正确的。

解决此问题的更通用方法是生成一个数字并将 map 生成到您想要的范围:

v = r.randint(0, 21 + 51)
value = v + 10 if v <= 20 else v - 21 + 50

如果要将输入指定为范围并在所有范围内获得均匀分布,则可以这样概括:

def from_ranges(*ranges):
    n = sum(map(len, ranges))
    v = random.randrange(n)
    for range in ranges:
        k = len(range)
        if v < k:
            return range[v]
        v -= k

这很好,因为范围是不占用大量空间的小对象,但在您可以指定的内容方面为您提供了很大的灵活性。

对于您问题中的示例,您可以将 function 称为

>>> from_ranges(range(10, 31), range(50, 101))

您还可以通过将长度累加到累积和中来消除最终的线性搜索,以支持二进制搜索:

from bisect import bisect
from itertools import accumulate
from random import randrange

def from_ranges(*ranges):
    lengths = list(accumulate(map(len, ranges)))
    v = randrange(lengths[-1])
    r = bisect(lengths, v)
    offset = lengths[r - 1] if r > 0 else 0
    return ranges[r][v - offset]

如果您要在生成随机数之前记住累积,此解决方案会更快。 否则,它与第一个解决方案相比几乎没有优势。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM