[英]A random generator with non-repeating elements and changing range
我想实现一个随机生成器,以便它能够生成从 0 到 n 的随机数,但除非范围用尽,否则它不应该返回已返回的元素。 例如,如果范围是从0到7,并且上一代是4,那么在返回0-7中的所有整数之前,4不会出现在随机生成中。 这是我到目前为止所拥有的 - 我将生成的元素交换到数组的前面并缩小范围。
现在我必须实现一个 function 以在生成时更改随机生成的范围,并且在更改范围后非重复条件仍然成立。 function 采用下限和上限,表示新范围,可以小于或大于旧范围。 比如返回4后,我把范围改成2到7,那么列表2-7用完后,4就不会出现在生成中了。
我不知道这样做最有效的方法是什么。 我试图创建一个黑名单并在该范围内重新生成一个数组,其中的数字不在黑名单中,但是在列表用完后重置数组时遇到了一些问题。
class RandomGenerator:
def __init__(self, n):
self.n = n
self.start = 0
self.arr = list(range(n+1))
def generate(self):
if self.start > self.n:
self.arr = list(range(n+1))
r = random.randint(self.start, self.n)
out = self.arr[r]
temp = self.arr[self.start]
self.arr[self.start] = self.arr[r]
self.arr[r] = temp
self.start += 1
return out
对于小的n
,您可以生成一个数字列表, shuffle
它,然后pop
元素; 当它用尽时,生成一个新的source
,然后重复。
import random
def get_random_without_repeats(n=8):
source = []
while True:
if not source:
source = list(range(n))
random.shuffle(source)
yield source.pop()
for elt in get_random_without_repeats():
print(elt)
您可以添加更复杂的逻辑以在耗尽后重新生成源,以满足您的需求。 例如,以下示例在每次源耗尽时从底部缩小值的范围
import random
def get_random_without_repeats(n=8):
source = []
turn = 0
while True:
if not source:
source = list(range(turn, n))
if not source:
return StopIteration
turn += 1
random.shuffle(source)
yield source.pop()
for elt in get_random_without_repeats():
print(elt)
除非我遗漏了一些明显的东西,否则你可以在生成器中无休止地从random.sample
中提取数字——它们保证永远不会重复,如果你迭代像itertools.cycle
这样的无限迭代器,你就可以拥有可能的数字池用尽给定范围内的所有数字后“重置”:
from itertools import islice
def get_numbers(minimum, maximum):
# minimum and maximum are inclusive
from itertools import cycle
from random import sample
for generator in cycle([sample]):
yield from generator(range(minimum, maximum+1), k=maximum+1)
print(list(islice(get_numbers(0, 7), 16)))
Output:
[0, 1, 4, 3, 7, 2, 6, 5, 1, 6, 0, 3, 7, 4, 5, 2]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.