最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to get the nth value of a JavaScript generator? - Stack Overflow

programmeradmin0浏览0评论

How can I get the nth value of a generator?

function *index() {
  let x = 0;
  while(true)
    yield x++;
}

// the 1st value
let a = index();
console.log(a.next().value); // 0

// the 3rd value
let b = index();
b.next();
b.next();
console.log(b.next().value); // 2

// the nth value?
let c = index();
let n = 10;
console.log(...); // 9

How can I get the nth value of a generator?

function *index() {
  let x = 0;
  while(true)
    yield x++;
}

// the 1st value
let a = index();
console.log(a.next().value); // 0

// the 3rd value
let b = index();
b.next();
b.next();
console.log(b.next().value); // 2

// the nth value?
let c = index();
let n = 10;
console.log(...); // 9
Share Improve this question asked May 23, 2015 at 7:57 MulanMulan 135k34 gold badges238 silver badges274 bronze badges 1
  • 4 Have you tried a loop? – Bergi Commented May 23, 2015 at 8:00
Add a comment  | 

5 Answers 5

Reset to default 6

You can define an enumeration method like in python:

function *enumerate(it, start) {
   start = start || 0;
   for(let x of it)
     yield [start++, x];
}

and then:

for(let [n, x] of enumerate(index()))
  if(n == 6) {
    console.log(x);
    break;
  }

http://www.es6fiddle.net/ia0rkxut/

Along the same lines, one can also reimplement pythonic range and islice:

function *range(start, stop, step) {
  while(start < stop) {
    yield start;
    start += step;
  }
}

function *islice(it, start, stop, step) {
  let r = range(start || 0, stop || Number.MAX_SAFE_INTEGER, step || 1);
  let i = r.next().value;
  for(var [n, x] of enumerate(it)) {
    if(n === i) {
      yield x;
      i = r.next().value;
    }
  }
}

and then:

console.log(islice(index(), 6, 7).next().value);

http://www.es6fiddle.net/ia0s6amd/

A real-world implementation would require a bit more work, but you got the idea.

As T.J. Crowder pointed out, there is no way to get to the nth element directly, as the values are generated on demand and only the immediate value can be retrieved with the next function. So, we need to explicitly keep track of the number of items consumed.

The only solution is using a loop and I prefer iterating it with for..of.

We can create a function like this

function elementAt(generator, n) {
    "use strict";

    let i = 0;

    if (n < 0) {
        throw new Error("Invalid index");
    }

    for (let value of generator) {
        if (i++ == n) {
            return value;
        }
    }

    throw new Error("Generator has fewer than " + n + " elements");
}

and then invoke it like this

console.log(elementAt(index(), 10));
// 10

Another useful function might be, take, which would allow you to take first n elements from a generator, like this

function take(generator, n) {
    "use strict";

    let i = 1,
        result = [];

    if (n <= 0) {
        throw new Error("Invalid index");
    }

    for (let value of generator) {
        result.push(value);
        if (i++ == n) {
            return result;
        }
    }

    throw new Error("Generator has fewer than " + n + " elements");
}

console.log(take(index(), 10))
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

A simple loop will do:

let n = 10,
    iter = index();
while (--n > 0) iter.next();
console.log(iter.next().value); // 9

ECMAScript 2025 update: we now have iterator helper method drop, and so we can now do:

const iter = gen(); // Generators return iterator helper objects
const value = iter.drop(n - 1).next().value

drop returns an iterator that, when its first value is consumed, consumes the first n-1 values of the original iterator, ignoring them, and then yields the next one.

No array is created. If you want to have all first

发布评论

评论列表(0)

  1. 暂无评论