# How to use for of loop with two iterators

## Issue

I’m looking for a way to do something similar to Python :

``````for a,b in zip(c,d) :
``````

I’m trying to do it with the for… of loop in javascript but I just can’t find how… something like :

``````const b = [2,3,5]
const d = [['e1' , 'e2' , 'e3'], ['i1', 'i2'],
['o1', 'o2', 'o3', 'o4']]

for (const a of b, const c of d) {
instruction(a,c)
}
``````

Thanks

## Solution

If I look up the zip function, it just combines each entry by index, you should be able to simulate that easily enough with a normal function, but to keep the iterator aspect of it, you can use a generator function

``````const b = [2,3,5];
const d = [['e1' , 'e2' , 'e3'], ['i1', 'i2'],
['o1', 'o2', 'o3', 'o4']];

function *zip( ...iterables ) {
const inputs = iterables.map( iterator => Array.isArray( iterator ) ? iterator : Array.from( iterator ) );
const size = Math.min( ...inputs.map( i => i.length ) );
for (let i = 0; i < size; i++) {
yield inputs.map( input => input[i] );
}
}

console.log( 'iterating with arrays' );
for (const entry of zip(b, d)) {
console.log( entry );
}

console.log( 'iterating with other iterators' );
for (const entry of zip(b, zip(b, d))) {
console.log( entry );
}``````

What did bug me about the above answer is that it will potentially read through any iteratable at the start already, making it potentially inefficient (depending on the size of the input, and how complex each iteration is)

So thinking about this, instead of making all the iterators an array, and evaluate them like this, it actually makes more sense to make use of `[Symbol.iterator]` on every argument and then go through the iterations one by one.

I added a simple `nextNumberGenerator` that creates an array of up to max numbers to prove the point. In the original answer, it would have iterated all max numbers before any result comes available, but with the updated functionality, it will only evaluate as far as other combinations are possible

I only added a test still with a `Set` argument, and did some input validation on it. So if you use this code somewhere, be sure to write your own tests for your use cases ðŸ™‚

``````const b = [2, 3, 5];
const d = [['e1', 'e2', 'e3'], ['i1', 'i2'],
['o1', 'o2', 'o3', 'o4']];
const set = new Set(['Angus', 'Bob', 'Daisy']);

function* nextNumberGenerator(max) {
let current = 0;
while (current < max) {
console.log('returning ' + current + ' of ' + max);
yield current++;
}
}

function* zip(...iterables) {
const inputs = iterables.map(iterator => iterator[Symbol.iterator] ? iterator[Symbol.iterator]() : null);

if (inputs.some(v => v === null)) {
throw new Error('ArgumentException: At least one argument is not iterable');
}

let done = false;
while (!done) {
const result = [];
for (const iterator of inputs) {
const value = iterator.next();
if (value.done) {
done = true;
break;
}
result.push(value.value);
}
if (!done) {
yield result;
}
}
}

console.log('iterating with arrays');
for (const entry of zip(b, d, set)) {
console.log(entry);
}

console.log('iterating with other iterators');
for (const entry of zip(b, zip(b, d), nextNumberGenerator(10), set)) {
console.log(entry);
}``````

Also observe, this will only handle synchronous iterables, but no asynchronous ones.

For more information on the iterables, you can have a look here: