[英]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); 然后,要选择一个随机数,我们可以执行以下操作:
现在,考虑三个大小不等的范围,比如 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.