簡體   English   中英

具有非重復元素和變化范圍的隨機發生器

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM