我想實作一個隨機生成器,以便它能夠生成從 0 到 n 的亂數,但除非范圍用盡,否則它不應回傳已回傳的元素。例如,如果范圍是從 0 到 7,并且上一代是 4,那么在回傳 0-7 中的所有整數之前,4 不會出現在隨機生成中。這是我到目前為止所擁有的 - 我將生成的元素交換到陣列的前面并縮小范圍。
現在我必須實作一個函式來在生成時更改隨機生成的范圍,并且在更改范圍后非重復條件仍然成立。該函式采用下限和上限,指示新范圍并且可以小于或大于舊范圍。比如回傳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
編輯:這里我通過黑名單的方式實作了更改范圍功能。我不確定它是否是一個有效的解決方案,但它絕對不是有效的,因為我每次呼叫函式 generate 時都會生成一個新陣列。我不知道如何使用交換元素的原始方法或者是否可能。
import random
class RandomGenerator():
def __init__(self, lower, upper):
self.lower = lower
self.upper = upper
self.arr = list(range(lower, upper 1))
self.blacklist = []
def generate(self):
if not self.arr:
self.arr = list(range(self.lower, self.upper 1))
n = len(self.arr)-1
r = random.randint(0, n)
out = self.arr[r]
self.blacklist.append(out)
self.arr = [x for x in self.arr if x not in self.blacklist]
return out
def change_range(self, lower, upper):
self.lower = lower
self.upper = upper
gen = RandomGenerator(4, 7)
print(gen.generate())
print(gen.generate())
print(gen.generate())
print(gen.generate())
print(gen.generate())
gen.change_range(2, 7)
print(gen.generate())
print(gen.generate())
print(gen.generate())
uj5u.com熱心網友回復:
對于 small 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)
uj5u.com熱心網友回復:
除非我遺漏了一些明顯的東西,否則您可以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)))
輸出:
[0, 1, 4, 3, 7, 2, 6, 5, 1, 6, 0, 3, 7, 4, 5, 2]
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/391716.html
