Как рандомизировать вывод генератора в JavaScript? - PullRequest
3 голосов
/ 27 мая 2019

Давайте представим, что у меня есть генератор, который в итоге останавливается

function* letters () {
  let offset = 0
  while (offset < 26)
    yield String.fromCharCode(65 + offset++)
}

console.log(Array.from(letters()))
// => [ "A", "B", "C", ..., "X", "Y", "Z" ]

Используя этот генератор в качестве входных данных, я хочу создать другой генератор, но для этого я бы хотел, чтобы значения выводились в случайном порядке

function* randomizeGen (gen) {
  // ...
}

Array.from(randomizeGen(letters()))
// => [ "X", "T", "L", "P", "A", ..., "G", "S", "B" ] (all 26 letters)

Новый генератор должен быть ленивым, как и первый, но я не могу понять, как написать его умным способом

function shuffleArray (arr) {
  // return shuffled array
}

function* randomizeGen (gen) {
   const all = Array.from(gen) // help!
   for (const one of shuffleArray(all))
     yield one
}

Это бы сработало, но это было сделано, сначала полностью исчерпав gen. В действительности, мой первоначальный генератор выводит миллионы значений , поэтому я не думаю, что собирать их все в массив сначала - хорошая идея. Смысл использования генератора в том, что я могу обрабатывать значения по одному

Честно говоря, я понятия не имею, как рандомизировать выходной сигнал генератора, но в то же время держу его ленивым. Может кто-нибудь помочь, пожалуйста?

Ответы [ 2 ]

1 голос
/ 27 мая 2019

Вы не можете по определению.Генератор генерирует одно значение в определенном порядке каждый раз, когда оно вызывается.Поэтому, если вам нужно другое значение, а не следующее в строке, вам придется использовать несколько значений из генератора, а затем выбрать одно для возврата.Это скорее оценка, чем лень.


Однако вы можете смоделировать предполагаемое поведение, как это.Это останется ленивым в течение приблизительно 50% времени.Так что это своего рода ленивый.

Обратите внимание, что это далеко не случайный порядок.Первая половина элементов в генераторе будет иметь 50% -й шанс быть помещенным в правильном порядке (и 50% -ый шанс быть помещенным в кэш).В то время как вторая половина элементов будет иметь 2/n шанс быть размещенным в правильном порядке (где n - текущее количество элементов в кэше, aka n изменится с N/2 до 0 (где N - общее количество элементов в генераторе)).

TL: DR первая половина «случайного» результата будет в порядке, но здесь и там будет отсутствовать пара элементов (они появляются в другой половине).

Math.random.between = (min, max) => Math.floor(Math.random()*(max-min+1)+min);

function* letters () {
  let offset = 0
  while (offset < 26)
    yield String.fromCharCode(65 + offset++)
}

function* randomizeGen (gen) {
   let cache = [];
   let current = gen.next();
   
   while (!current.done) {
    if (Math.random.between(0, 1) > 0.5) {
      yield current.value;
    } else {
      cache.push(current);
    }
    current = gen.next();
   }
   
   while (cache.length > 0) {
    const index = Math.random.between(0, cache.length-1);
    const v = cache[index];
    cache = cache.filter((_,i) => i !== index);
    yield v.value;
   }
}

const randomOrder = Array.from(randomizeGen(letters()));
console.log(randomOrder);
0 голосов
/ 27 мая 2019

Я не уверен, что это лучший подход. Но вы можете использовать приведенный ниже код для генерации алфавитов в случайном порядке

function* letters() {
    let arr = [];
    let char = "";
    while (arr.length < 26) {
        let flag = true;
        while (flag) {
            char = String.fromCharCode(65 + Math.floor(Math.random() * 27));
            if (!arr.find(function(element){return element === char;})){
                arr.push(char);
                flag = false;
            }
        }
    yield char;
    }
}

console.log(Array.from(letters()))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...