1

I am playing with iterators in javascript. I found a way of chaining them so I don't have to nest them, just for readability.

It kind of works exactly like an array map chain.

What I like to do is distribute the items of the generator over a few sub iterators, catch the results and feed them to the next iterator. Such that the outcome will be this:

4
6
8
7
9
11

Given this piece of code:

"use strict";

const _ = require('lodash');

let things = chain([
    gen,
    addOne,
    distribute([
        addOne,
        addTwo,
        addThree
    ]),
    addOne
]);

for(let thing of things) {
    console.log(thing);
}

//////////////// DEFENITIONS ////////////////////

function* gen() {
    yield* [1, 2, 3, 4, 5, 6];
}

function* addOne(iterator) {
    for(let item of iterator) {
        yield (item + 1)
    }
}

function* addTwo(iterator) {
    for(let item of iterator) {
        yield (item + 2)
    }
}

function* addThree(iterator) {
    for(let item of iterator) {
        yield (item + 3)
    }
}

const distribute = _.curry(function* (iterators, iterator) {
    // magic
});

function chain(iterators) {
    return iterators.reduce((prevIterator, thisIterator, index) => {
        if(index === 0) {
            return thisIterator();
        }
        return thisIterator(prevIterator);
    }, null);
}

Eventually i would like to add a distribution function to the distribution iterator, so it can determine which item to pass to which subiterator. For now it is just based on the order.

Question: How do I write a distribution iterator that takes a few subiterators as an argument and passes the results through to the next iterator.

Erik
  • 307
  • 1
  • 9
  • Sorry, I don't get at all what you want `distribute` to do. – Bergi Feb 03 '18 at 17:18
  • Sorry if I have been unclear. The generator is providing integers. I want to send 1 and 4 to iterator `addOne`, 2 and 5 to the iterator `addTwo` and 3 and 6 to iterator `addTrhee`. – Erik Feb 03 '18 at 20:16
  • Ah, I see. So you basically want to [`tee`](https://stackoverflow.com/q/46416266/1048572) them and then zip/flatten them back together. – Bergi Feb 03 '18 at 20:26
  • Hmm I was not familiar with the concept of tee. I will read in to it. Thnx! – Erik Feb 03 '18 at 21:11

1 Answers1

0

It seems overly complex, but it works

const distribute = _.curry(function* (iterators, mainIterator) {
    let iteratorIndex = 0;
    let done = [];
    for(let iterator of iterators) {
        iterators[iteratorIndex] = iterator(mainIterator);
        done.push(false);
        iteratorIndex++;
    }
    while(true) {
        let iteratorIndex = 0;
        for(let iterator of iterators) {
            let next = iterator.next();
            done[iteratorIndex] = next.done;
            if(!next.done) {
                yield next.value;
            }
            iteratorIndex++;
        }
        if(done.every(done => done)) {
            return;
        }
    }
});

And finally with a distribution function:

const distribute = _.curry(function* (genIteratorIndex, iterators, mainIterator) {
    let iteratorIndex = 0;
    let done = [];

    // instantiate iterators
    for(let iterator of iterators) {
        iterators[iteratorIndex] = iterator(mainIterator);
        done.push(false);
        iteratorIndex++;
    }

    // Pass stuff through
    while(true) {
        let next = iterators[genIteratorIndex.next().value].next();
        done[iteratorIndex] = next.done;
        if(!next.done) {
            yield next.value;
        }
        if(done.every(done => done === true)) {
            return;
        }
    }
});

function* subSequent(len) {
    let curr = 0;
    while(true) {
        if(curr === len) {
            curr = 0;
        }
        yield curr;
        curr++;
    }
}


let things = chain([
    gen,
    addOne,
    distribute(subSequent(3), [
        addOne,
        addTwo,
        addThree
    ]),
    addOne
]);
Erik
  • 307
  • 1
  • 9