Search code examples
javascriptiteratorpeek

How to peek at the next value in a Javascript Iterator


Let's say I have an iterator:

function* someIterator () {
    yield 1;
    yield 2;
    yield 3;
}

let iter = someIterator();

... that I look at the next element to be iterated:

let next = iter.next(); // {value: 1, done: false}

... and I then use the iterator in a loop:

for(let i of iterator)
    console.log(i); 
// 2
// 3

The loop will not include the element looked at. I wish to see the next element while not taking it out of the iteration series.

In other words, I wish to implement:

let next = peek(iter); // {value: 1, done: false}, or alternatively just 1

for(let i of iterator)
    console.log(i); 
// 1
// 2
// 3 

... and I wan't to do it without modifying the code for the iterable function.

What I've tried is in my answer. It works (which is why I made it an answer), but I worry that it builds an object that is more complex than it has to be. And I worry that it will not work for cases where the 'done' object is something different than { value = undefined, done = true }. So any improved answers are very much welcome.


Solution

  • Just a bit different idea is to use wrapper that makes an iterator kind of eagier.

    function peekable(iterator) {
      let state = iterator.next();
    
      const _i = (function* (initial) {
        while (!state.done) {
          const current = state.value;
          state = iterator.next();
          const arg = yield current;
        }
        return state.value;
      })()
    
      _i.peek = () => state;
      return _i;
    }
    
    function* someIterator () { yield 1; yield 2; yield 3; }
    let iter = peekable(someIterator());
    
    let v = iter.peek();
    let peeked = iter.peek();
    console.log(peeked.value);
    
    for (let i of iter) {
      console.log(i);
    }