Я пытаюсь создать генератор, который возвращает числа в заданном диапазоне, которые проходят конкретный тест, заданный функцией foo. Однако я хотел бы, чтобы номера проверялись в произвольном порядке. Следующий код достигнет этого:
from random import shuffle
def MyGenerator(foo, num):
    order = list(range(num))
    shuffle(order)
    for i in order:
        if foo(i):
            yield i
Эта проблема
 Проблема с этим решением заключается в том, что иногда диапазон будет довольно большим (num может быть порядка 10**8 и выше). Эта функция может стать медленной, имея такой большой список в памяти. Я попытался избежать этой проблемы со следующим кодом:
from random import randint    
def MyGenerator(foo, num):
    tried = set()
    while len(tried) <= num - 1:
        i = randint(0, num-1)
        if i in tried:
            continue
        tried.add(i)
        if foo(i):
            yield i
 Это работает хорошо в большинстве случаев, так как в большинстве случаев num будет довольно большим, foo будет принимать разумное количество чисел, а общее количество раз, __next__ будет __next__ методом __next__, будет относительно небольшим (скажем, не более 200 часто значительно меньше). Поэтому разумно предположить, что мы наткнемся на значение, которое проходит тест foo и размер tried никогда не становится большим. (Даже если она пропускает только 10% времени, мы не ожидали бы tried получить больше, чем примерно 2000 примерно.)
 Однако, когда num мал (близок к количеству раз, что __next__ метод вызывается, или foo терпит неудачу большую часть времени, указанное решение становится очень неэффективным - случайно угадывая номера, пока он не предполагает тот, который не tried.
Мое решение...
 Я надеялся использовать какую-то функцию, которая отображает числа 0,1,2,..., n на себя грубо случайным образом. (Это не используется для каких-либо целей безопасности, и поэтому не имеет значения, является ли это не самая "случайная" функция в мире). Функция здесь (создание случайной биективной функции, которая имеет тот же домен и диапазон) отображает на себя 32-битные целые числа, но я не уверен, как адаптировать отображение к меньшему диапазону. Учитывая num мне даже не нужна биекция на 0,1,..num только значение n больше, чем и 'close' to num (используя любое определение закрытия, которое вы считаете нужным). Тогда я могу сделать следующее:
def mix_function_factory(num):
    # something here???
    def foo(index):
        # something else here??
    return foo
def MyGenerator(foo, num):
    mix_function = mix_function_factory(num):
    for i in range(num):
        index = mix_function(i)
        if index <= num:
            if foo(index):
                yield index
 (до тех пор, пока биекция не находится на множестве чисел, массой больше, чем num число index <= num не верно, будет небольшим).
Мой вопрос
Можете ли вы подумать об одном из следующих:
-  Потенциальное решение для mix_function_factoryили даже несколько других потенциальных функций дляmix_functionкоторые я мог бы попытаться обобщить для разных значенийnum?
- Лучший способ решить исходную проблему?
Спасибо заранее....
