admin管理员组文章数量:1414851
With arrays in javascript, getting the current index for iteration is easy. You can either use forEach
and the index is the second entry, or use for...of
and .entries()
and array unpacking.
But generators have no .entries()
method. How do I get the current index for a generator in my for...of
loop?
I basically want:
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
With arrays in javascript, getting the current index for iteration is easy. You can either use forEach
and the index is the second entry, or use for...of
and .entries()
and array unpacking.
But generators have no .entries()
method. How do I get the current index for a generator in my for...of
loop?
I basically want:
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
Share
Improve this question
asked Dec 8, 2018 at 21:37
CobertosCobertos
2,26327 silver badges45 bronze badges
4 Answers
Reset to default 5In 2024 I'm updating this answer from 2018 with the mention of the Iterator helpers feature in stage 3 that is getting support (Node 22.9+, Chrome/Edge 122+, Opera 108+). The set of Iterator prototype functions includes a forEach
method, which provides the index to the callback function:
// Demo
function* myGen(){
let i = 64;
while(i < 70) {
i+=1;
yield String.fromCharCode(i);
}
}
myGen().forEach((value, index) => {
console.log(value, index);
});
Original answer from 2018:
It is not advisable to add things to a built-in prototype, but if you really want your code to work like that (calling .entries()
on any generator), then you could proceed as follows:
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 [index, value] of myGen().entries()) { //<-- Now you have .entries() on a Generator
console.log(index, value);
}
It is more prudent however to define a utility function.
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 [index, value] of GeneratorUtils.entriesOf(myGen())) {
console.log(index, value);
}
There's no built-in way to do it - the generator will have to yield something that contains the index. For example:
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);
}
If you can't modify a generator that you want to also get the index of, you can put it inside another generator that does keep track of the index (or you could just increment on every iteration outside):
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);
}
A slightly different approach might be to make myGen()
a regular function that returns an object adhering to the iterator protocol rather than a generator. Then you can just give it an entries()
method. It will work a little differently than a generator (you can't call next()
on it directly). But it be self-contained and should work as expected in situations where an iterator is expected:
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}`)
}
But generators have no
.entries()
method. How do I get the current index for a generator in myfor...of
loop?
You can utilize spread element preceding generator function call within an array literal and .entries()
method of 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);
}
本文标签: javascriptHow to iterate over a generator with indexesStack Overflow
版权声明:本文标题:javascript - How to iterate over a generator with indexes? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745223738a2648511.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论