繁体   English   中英

Python-如何生成具有多个范围的随机整数?

[英]Python- How to generate random integers with multiple ranges?

我在从不同的 (a,b) 集生成 X 数量的随机整数时遇到了困惑。 例如,我想生成来自 (1,5)、(9,15) 和 (21,27) 的 5 个随机整数。 我的代码生成 5 个随机整数,但仅在 21 到 27 之间,而不是其他两个。 理想情况下,我希望看到类似 1,4,13,22,25 而不是 21,21,25,24,27 的东西。

我的代码:

from random import randint
n = 0
while n < 5:
    n += 1
    for i in (randint(1,5),randint(9,15),randint(21,27)):
        x = i
    print i

不理想

from random import randint, choice

for _ in range(5):
    print(choice([randint(1,5),randint(9,15),randint(21,27)]))

正如 Blender 所说 - 更清晰的版本

from random import randint, choice

for _ in range(5):
    r = choice([(1,5),(9,15),(21,27)])
    print(randint(*r))

你好!

这是个有趣的问题; 当您意识到要实现真正的随机性,选择特定范围的概率必须由该范围的长度来衡量时,就会变得很有趣。

等长范围:

如果三个范围的长度相等,则说 range(0, 10), range(20, 30) 和 range(40, 50); 然后,要选择一个随机数,我们可以执行以下操作:

  1. 随机选择一个范围。
  2. 从该范围中选择一个随机数。

不等长的范围:

现在,考虑三个大小不等的范围,比如 range(0, 2)、range(4, 6) 和 range(10, 100);

第三个范围比前两个范围大得多。 如果我们采用与处理等长范围相同的策略,我们将倾向于从前两个范围中选择数字。

为了从三个不等长的范围中挑选真正的随机数,有两种策略。

策略 1:使用概率

选择一个范围的概率应该使得选择一个数字的概率保持不变。 我们可以通过权衡更短距离的可能性来实现这一点。

然而,不是计算概率权重; 有一个更好的解决方案。 参见策略 2。

策略 2:合并范围

我们可以简单地将三个范围合并为一个范围。 然后,从合并范围中随机选择一个数字。 这很简单:

import random;
def randomPicker(howMany, *ranges):
    mergedRange = reduce(lambda a, b: a + b, ranges);
    ans = [];
    for i in range(howMany):
        ans.append(random.choice(mergedRange));
    return ans;

让我们看看它的实际效果:

>>> randomPicker(5, range(0, 10), range(15, 20), range(40, 60));
[47, 50, 4, 50, 16]
>>> randomPicker(5, range(0, 10), range(70, 90), range(40, 60));
[0, 9, 55, 46, 44]
>>> randomPicker(5, range(0, 10), range(40, 60));
[50, 43, 7, 42, 4]
>>> 

randomPicker另一个好处是它可以处理任意数量的范围。

希望这可以帮助。

for i in (randint(1,5),randint(9,15),randint(21,27)):
    print i

这个 for 循环将生成 3 个随机数,一个来自提供的第一个范围,另一个用于第二个范围,最后一个用于最后一个范围,并在输出中打印每个。 您的打印不在 for 循环中,只打印给定的最后一个范围中的最后一个随机数。

import itertools, random
nums = list(itertools.chain(
            range(1,5),
            range(9,15),
            range(21,27)))
random.choices(nums, k=5)

对于非重复数字:

from random import randint, choice

randoms = []
counter = 0    
while True:
   new_random = (choice([randint(1,5),randint(9,15),randint(21,27)]))
   if new_random not in randoms:
      randoms.append(new_random)
      counter += 1
   if counter == 5 :
      break
print randoms

这里有一些有趣的答案,尽管我认为这个问题可以用更少的代码来解决,即使它的可读性稍差。

这里的基本思想是你有固定数量的选择,所以你基本上可以有一个范围来完成这项工作,然后将结果绘制到你想要的范围内。 或者,如果您想换一种方式考虑,创建一个函数f(x) -> y归结为相同的事情。

from random import randint

for i in xrange(5):
    n = randint(1,19)
    if n > 12:
        print(n + 8)
    elif n > 5:
        print(n + 3)
    else:
        print(n)

或者,使用一个函数:

from random import randint

def plot_to_ranges(n):
    if n > 12:
        return n + 8
    elif n > 5:
        return n + 3
    else:
        return n

for i in xrange(5):
    n = randint(1,19)
    print(plot_to_ranges(n))

如果您使用的是 Python 3.x,您应该将xrange更改为range

Sumukh Barve 的回答的补充:

策略 3:在不连接范围的情况下选择范围的成员

此方法对指定范围的长度求和。 然后它产生一个在该范围内的随机整数。 然后它根据它相对于范围的位置添加到该整数。

示例:如果范围是 (1,3) 和 (5,9),其中范围包括在内。 将所有范围的长度相加得到 3+4=7。 然后我们创建一个介于 1 到 7(或 0 到 6)之间的随机整数。 假设我们得到 2,我们从第一个范围中选择第二个项目。 如果我们得到 5,我们从第二个范围中选择第二个项目。

def randint_within_ranges(ranges):
    """ranges is a list of tuples, where each tuple is a range. E.g. [(0, 2), (4, 6), (10, 100)]. 
    Ranges must be non-overlapping. 
    Ranges are inclusive (e.g. can return 4 or 6).
    Returns a random int anywhere in any of those ranges. 
    (In this example, high probability will be from (10,100) range.)
    """
    #in case ranges aren't ordered, sort them now. Lowest first, e.g. [(0, 2), (4, 6), (10, 100)]
    ranges = sorted(ranges, key=min)
    #print('ranges',ranges)
    total_range_size = sum([abs(range_[1]-range_[0])+1 for range_ in ranges])
    #print('total_range_size',total_range_size)
    lowest_range_start = min([min(range_) for range_ in ranges])
    #print('lowest_range_start',lowest_range_start)
    randint = random.randint(0, total_range_size-1) 
    #print('randint',randint)
    randint += lowest_range_start
    #print('randint',randint)

    #add the gaps
    for i in range(len(ranges)-1):
        if randint > max(ranges[i]):
            randint += (min(ranges[i+1])-max(ranges[i])-1)#gaps[i]
        
    return randint

print(  randint_within_ranges([ (4, 6), (-300, -290), (285,289), (10, 15), (48,53), (85,91)])  )

您可以使用以下方法测试这仅返回范围内的数字。 范围包括两个边界。

randints = set()
for i in range(1000): 
    randints.add(randint_within_ranges([ (4, 6), (-300, -290), (285,289), (10, 15), (48,53), (85,91)]))
print(len(randints), sorted(list(randints)))

暂无
暂无

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

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