skip to Main Content

I am currently modifying some code and trying to not mess with the initial structure code. Having a for...of loop over an array, and having a second array with an identical structure, I am wondering if there is a quick way to make a generator over my second array to simulate a zip.

Here’s an example:

const firstArray = ["a", "b", "c"];
const myAdditionalArray = [1, 2, 3];
// const generatorOverMyAdditionalAray = ???
for (const item of firstArray) {
  // Initial code doing stuff with item
  const additionalItem = myAdditionalArray.next();  
  // More code doing stuff with item and additionalItem
}

For pythonistas, it would look something like that

>>> a = ["a", "b", "c"]
>>> b = [1, 2, 3]
>>> generator_over_b = (x for x in b)
>>> for item in a:
...     additional_item = next(generator_over_b)
...     print(item, additional_item)
... 
a 1
b 2
c 3

Edit: Added emphasis on why for or forEach loops are not a viable solution (and ultimately do not answer the question)

2

Answers


  1. Arrays have a values method for getting an iterator:

    const firstArray = ["a", "b", "c"];
    const generatorOverMyAdditionalAray = [1, 2, 3].values();
    for (const item of firstArray) {
      const additionalItem = generatorOverMyAdditionalAray.next().value;  
      console.log(item, additionalItem);
    }

    You could also implement a zip like generator, using [Symbol.iterator] — which is the method an object should have when it is iterable:

    function* zip(...args) {
        const iters = args.map(arg => arg[Symbol.iterator]());
        while (true) {
            const results = iters.map(iter => iter.next());
            if (results.some(({done}) => done)) break;
            yield results.map(({value}) => value);
        }
    }
    
    const arg1 = "abc";
    const arg2 = [1, 2, 3];
    const arg3 = new Set(["X", "Y", "Z"]);
    for ([a, b, c] of zip(arg1, arg2, arg3)) {
        console.log(a, b, c);
    }
    Login or Signup to reply.
  2. Array#values() gives an iterator over an array:

    const firstArray = ["a", "b", "c"];
    const myAdditionalArray = [1, 2, 3];
    
    const generatorOverMyAdditionalAray = myAdditionalArray.values();
    
    for (const item of firstArray) {
      // Initial code doing stuff with item
      const additionalItem = generatorOverMyAdditionalAray.next();  
      // More code doing stuff with item and additionalItem
      console.log(item, additionalItem.value);
    }

    In general, for..of uses the iteration protocol so using it on a value will fetch an iterator using the well-known @@iterator. For arrays, the symbol is aliased to .value, so the two are equivalent:

    const firstArray = ["a", "b", "c"];
    const myAdditionalArray = [1, 2, 3];
    
    const generatorOverMyAdditionalAray = myAdditionalArray[Symbol.iterator]();
    
    for (const item of firstArray) {
      // Initial code doing stuff with item
      const additionalItem = generatorOverMyAdditionalAray.next();  
      // More code doing stuff with item and additionalItem
      console.log(item, additionalItem.value);
    }

    The @@iterator symbol can be used with any iterable, for example, a set:

    const firstArray = ["a", "b", "c"];
    const myAdditionalSet = new Set()
      .add(1)
      .add(2)
      .add(1) //duplicate will be removed 
      .add(3);
    
    const generatorOverMyAdditionalAray = myAdditionalSet[Symbol.iterator]();
    
    for (const item of firstArray) {
      // Initial code doing stuff with item
      const additionalItem = generatorOverMyAdditionalAray.next();  
      // More code doing stuff with item and additionalItem
      console.log(item, additionalItem.value);
    }

    Or a string:

    const firstArray = ["a", "b", "c"];
    const myAdditionalString = "123";
    
    const generatorOverMyAdditionalAray = myAdditionalString[Symbol.iterator]();
    
    for (const item of firstArray) {
      // Initial code doing stuff with item
      const additionalItem = generatorOverMyAdditionalAray.next();  
      // More code doing stuff with item and additionalItem
      console.log(item, additionalItem.value);
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search