Eyal
Eyal

Reputation: 5848

How do I reuse a generator in ES6 javascript in for loops?

I'm trying to write a function that can take either a list or a generator as input. For example, this function:

function x(l) {
    for (let i of l) {
        console.log(i);
    }
    for (let i of l) {
        console.log(i);
    }
}

If I run it like this:

x([1,2,3])

It will display:

1
2
3
1
2
3

Now I want to use a generator as input:

function *y() {
    yield 5
    yield 6
    yield 7
}

These don't work:

x(y())
x(y)

The output is:

5
6
7
undefined

What do I need to do so that I can make it work?

In terms of Java, the function y above is a Generator and y() is an Iterator. [1,2,3] is a list and in Java, lists are generators. But the javascript for loop expects an iterator, which means that it can't be restarted. This seems like a flaw in javascript that the for loop works on iterators and not generators.

Upvotes: 2

Views: 2616

Answers (2)

Diego Perozo
Diego Perozo

Reputation: 31

   let tableData = {a:1, b:2};
   function* getKey() {
      let i = 0;
      while(true){
        let obj = Object.keys(tableData)
        yield obj[i]
        i++
        if (i >= obj.length){
          i = 0
        }
      }
    }
    let i = getKey()
    i.next().value //you can use this call for ever

Upvotes: 0

Bergi
Bergi

Reputation: 664297

A generator cannot be used multiple times. If you want to iterate it twice, you will need to create two generators by calling the generator function twice.

What you can do when your function expects an iterable (that is used in a for … of loop) is to create one on the fly from your generator function:

x({[Symbol.iterator]: y})

If you want to write your function x so that it can take either an iterator or a generator function, you can use something like

getIterator(val) {
    if (typeof val == "function") // see also  https://stackoverflow.com/q/16754956/1048572
        return val();
    if (typeof val[Symbol.iterator] == "function")
        return val[Symbol.iterator]();
    throw new TypeError("not iterable!")
}
function x(l) {
    for (let i of getIterator(l)) {
        console.log(i);
    }
    for (let i of getIterator(l)) { // call getIterator again
        console.log(i);
    }
}
x(y);

Upvotes: 4

Related Questions