Zip in Python

In mathematics, one can have a function \(f: X \times Y\to Z\) and write \(f(x,y) = z\), where \(x\in X, y\in Y, z\in Z\). Some books take care to remark that since \(X \times Y\) is the domain and \((x,y)\in X\times Y\), one should in fact write \(f((x,y))=z\). In Python, this distinction is accomplished using the star (*) in function calls. So for example if one had a sequence of parameters \((a_i)_{i=0}^n\), then one can write \[ f(\star(a_i)_{i=0}^n) = f(a_{0}, \ldots, a_n) \]

Now, the built-in function zip in Python takes the \(i\)th element from each iterable in some sequence, and forms a tuple for each \(i\), then places all these tuples in one final list. Concretely, suppose we are given some sequence \(x = ((x_{i,j})_{j={0}}^m)_{i={0}}^n\). Incidentally, this sequence can be visualized as an \((n+1)\times (m+1)\) matrix:

\[ \begin{pmatrix} (x_{0,0}, \ldots, x_{0,m}) \\ \vdots \\ (x_{n,0}, \ldots, x_{n,m}) \end{pmatrix} \]

Now let us examine what \(\mathrm{zip}(\star x)\) means. The star unpacks the first layer of the sequence, leaving us with \[ \mathrm{zip}((x_{0,0}, \ldots, x_{0,m}), \ldots, (x_{n,0}, \ldots, x_{n,m})) \] Now, \(\mathrm{zip}\) will first take the \(0\)th element from each argument, forming the sequence \((x_{0,0},\ldots,x_{n,0})\); then it will take the elements in position \(1\) from each argument, forming the sequence \((x_{0,1}, \ldots, x_{n,1})\); this process continues until we reach the sequence \((x_{0,m},\ldots,x_{n,m})\). Finally, \(\mathrm{zip}\) will place everything in a sequence of its own, and we obtain a new matrix: \[ \begin{pmatrix} (x_{0,0},\ldots,x_{n,0}) \\ \vdots \\ (x_{0,m},\ldots,x_{n,m}) \end{pmatrix} \] In other words, everything that was horizontal is now vertical, and the converse holds as well—that is, \(\mathrm{zip}\) maps each matrix \(x\) to its transpose \(x^T\) (or, more specifically, \(\mathrm{zip}\) maps each matrix \(x = (w_0, \ldots, w_n)^T\) with row-vectors \(w_0, \ldots, w_n\) to the matrix \((w_0^T, \ldots, w_n^T)\), and then forms row-vectors in the new matrix). If we decide to repeat this operation, we get the original matrix back. In other words, \(x = \mathrm{zip}(\star\mathrm{zip}(\star x))\).

To give an example of this identity in Python:

>>> x = (1, 2, 3)
>>> y = (4, 5, 6)
>>> lst = [x, y]
>>> lst == zip(*zip(*lst))
True

CC0
The content on this page is in the public domain.