Efficient zip function in JavaScript
Tags: javascript, python, functional, webdev
Published: 2021-10-31 13:20:20

# Efficient zip function in JavaScript

<!-- I find the `zip` in Python quite useful. -->

The Python `zip` function is a clever analogy of a real zipper: It allows you to iterate over multiple arrays element-wise without having to worry about indices. It is quite handy when you have to manually pair elements coming from two (or more) data sources:

```python
>>> scoreList = [5, 3, 6, 8]
>>> playerList = ['Mary', 'John', 'Emma', 'Gavin']
>>> list(zip(scoreList, playerList))
# [(5, 'Mary'), (3, 'John'), (6, 'Emma'), (8, 'Gavin')]
```

Please note the `list()` call is needed to convert the result to a list, otherwise it returns something like

```python
>>> zip(scoreList, playerList)
# <zip object at 0x109b19d00>
```

which is an object implementing the iterator interface. Why the hassle with this object? Why is it not just a list? The iterator interface allows lazy-evaluation, meaning it won't create a list, only if it's asked. This object instead allows generating elements on-demand, which can be more efficient. Let's say I want to find the first player with score 6:

```python
for score, player in zip(scoreList, playerList):
  if score == 6:
    print(f'player {player} has score 6')
    break
```

In this case, the iteration stops with (`(6, 'Emma')`) and the last pair (`(8, 'Gavin')`) would never be constructed.

The implementation is quite interesting, because `zip` not only works with two lists, it can more than two arrays as input parameters. This can be particularly useful when trying to transpose a list of lists (a matrix). If you're not familiar with the term `transpose`, it simply means a list of list is simply flipped by its diagonal. The transposition of

```python
[
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]
```

is

```python
>>> list(zip(*[
...  [1, 2, 3],
...  [4, 5, 6],
...  [7, 8, 9]
... ]))
[
  [1, 4, 7],
  [2, 5, 8],
  [3, 6, 9]
]
```

What happens if the input arrays do not have the same length? According to the [Python docs](https://docs.python.org/3.3/library/functions.html#zip) it _stops when the shortest input iterable is exhausted_, meaning it will return as many elements as long the shortest array is:

```python
>>> list(zip([1, 2, 3], [4, 5]))
[(1, 4), (2, 5)]
```

If all elements need to be returned, [itertools.zip_longest](https://docs.python.org/3/library/itertools.html#itertools.zip_longest) should be used.

And just to spice things up the little, let me mention that as the `zip` function expects iterables as input, not specifically arrays. Iterables are more generic than arrays, without going too much into the details, they are objects that can be iterated over one element at the time, and they can signal if they are exhausted (iteration finished). In practice, it means that any object that can be iterated over can be used as inputs of zip: tuples, sets, dictionaries, range, or even results of other zips. Mind-blowing, right? 🤯 It is also possible to create an infinite zip. Let me use [itertools.count](https://docs.python.org/3/library/itertools.html#itertools.count) to demonstrate it. It is very similar to `range()` except it has no stopping criteria, so if it is used in a for loop it keeps yielding values unless it is stopped.

```python
>>> for a, b in zip(itertools.count(start=0, step=2), itertools.count(start=1, step=2)):
...     print(a, b)
1 2
3 4
5 6
...
```

I really hope I could convince you by now, how cool and versatile this Python standard library function is. Why can't we have nice things in JavaScript? Well we can, you just probably end up hunting for third-parties on npm or ready-made solutions on Stack Overflow. But is there anything more satisfying than using your home-grown utilities? You can find it out on [my website](https://matyasfodor.com/blog/efficient-zip#how-javascript-could-do-it).