如何在JavaScript中随机化生成器输出?

时间:2019-05-27 16:51:01

标签: javascript generator

假装我有一个发电机,最终它会停止

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 个答案:

答案 0 :(得分:1)

根据定义,您不能。生成器每次被调用时都会按特定顺序生成一个值。因此,如果您需要其他值而不是行中的下一个值,则必须使用生成器中的多个值,然后选择一个值以返回。渴望评估而不是懒惰。


但是,您可以像这样模拟预期的行为。它会在大约50%的时间内保持懒惰状态。所以有点懒。

  

请注意,这与实际的随机顺序相差甚远。生成器中的元素的前半部分将有50%的机会以正确的顺序放置(而50%的机会被放入缓存)。尽管元素的后半部分有2/n的机会以正确的顺序放置(其中n是缓存中当前的元素数量,但n也将来自{{ 1}}至N/2(其中0是生成器中元素的总数)。

TL:DR“随机”结果的前半部分将是有序的,但在此处和那里缺少几个元素(它们出现在另一半)。

N

答案 1 :(得分:0)

我不确定这是否是最好的方法。但是您可以使用以下代码以随机顺序生成字母

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()))