首页 文章

如何使用索引迭代生成器?

提问于
浏览
0

使用javascript中的数组,获取迭代的当前索引很容易 . 您可以使用 forEach 并且索引是第二个条目,或使用 for...of.entries() 以及数组解包 .

但是生成器没有 .entries() 方法 . 如何在 for...of 循环中获取生成器的当前索引?

我基本上想要:

function* myGen(){
    let i = 0;
    while(true) {
        i+=1;
        yield i;
    }
}

for(let [j, index] of myGen().entries()) { //<-- I want .entries() but for a Generator
    //...
}
//Running the above produces TypeError: myGen(...).entries(...) is not a function or its return value is not iterable

3 回答

  • 0

    稍微不同的方法可能是使 myGen() 成为一个常规函数,它返回一个遵循迭代器协议而不是生成器的对象 . 然后你可以给它一个 entries() 方法 . 它的工作方式与生成器略有不同(你不能直接在它上面调用 next() ) . 但它是自包含的,并且应该在预期迭代器的情况下按预期工作:

    function myGen(start, stop){
       return  {
            [Symbol.iterator]: function* () {
                while(start < stop){
                    yield start++
                }
            },
            entries: function* entries (){
                let i = 0
                for (n of this){
                    yield [i++, n]
                }
            }
        }
    }
    
     
    let g = myGen(10, 20)
    // works like a regular iterator:
    console.log([...g])
    
    // but you can also call entries():
    g = myGen(2, 9)
    for ([i, n] of g.entries()){
      console.log(`index: ${i}, value: ${n}`)
    }
    
  • 3

    没有内置的方法 - 生成器必须产生包含索引的东西 . 例如:

    function* myGen(){
      let index = 0;
        while(index < 10) {
          const item = 'foo' + index;
          yield { item, index };
          index++;
        }
    }
    
    for(const { item, index } of myGen()) {
      console.log('item: ' + item);
      console.log('index: ' + index);
    }
    

    如果你不能修改你想要得到索引的生成器,你可以将它放在另一个跟踪索引的生成器中(或者你可以在每次迭代外部递增):

    function* unmodifiableGen(){
      // index is private, is not being yielded
      let index = 0;
      while(index < 10) {
        yield Math.random();
        index++;
      }
    }
    function* generatorCounter(gen) {
      // this index *will* be yielded:
      let index = 0;
      for (const item of gen()) {
        yield { item, index };
        index++;
      }
    }
    
    for(const { item, index } of generatorCounter(unmodifiableGen)) {
      console.log('item: ' + item);
      console.log('index: ' + index);
    }
    
  • 0

    不建议将内容添加到内置原型中,但如果您真的希望代码能够像这样工作(在任何生成器上调用 .entries() ),那么您可以按以下步骤操作:

    const Generator = Object.getPrototypeOf(function* () {});
    
    Generator.prototype.entries = function * () {
        let i = 0;
        for (let value of this) {
            yield [i++, value];
        }
    }
    
    // Demo
    function* myGen(){
        let i = 64;
        while(i < 70) {
            i+=1;
            yield String.fromCharCode(i);
        }
    }
    
    for(let [j, index] of myGen().entries()) { //<-- Now you have .entries() on a Generator
        console.log(j, index);
    }
    

    然而,定义效用函数更为谨慎 .

    const GeneratorUtils = {
        * entriesOf(iter) {
            let i = 0;
            for (let value of iter) {
                yield [i++, value];
            }
        }
    };
    
    // Demo
    function* myGen(){
        let i = 64;
        while(i < 70) {
            i+=1;
            yield String.fromCharCode(i);
        }
    }
    
    for(let [j, index] of GeneratorUtils.entriesOf(myGen())) {
        console.log(j, index);
    }
    

相关问题