Как перебрать генератор с индексами? - PullRequest
0 голосов
/ 09 декабря 2018

С массивами в 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

Ответы [ 4 ]

0 голосов
/ 30 января 2019

Но у генераторов нет метода .entries().Как получить текущий индекс для генератора в моем цикле for...of?

Вы можете использовать элемент расширения, предшествующий вызову функции генератора, в литерале массива и метод .entries() из Array.prototype

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

for (const [index, value] of [...myGen()].entries()) {
  console.log(index, value);
}
0 голосов
/ 09 декабря 2018

Не рекомендуется добавлять что-либо во встроенный прототип, но если вы действительно хотите, чтобы ваш код работал так (вызывая .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);
}
0 голосов
/ 09 декабря 2018

Несколько иной подход мог бы сделать 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}`)
}
0 голосов
/ 09 декабря 2018

Нет встроенного способа сделать это - генератор должен будет дать что-то, что содержит индекс.Например:

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);
}
...