# unzip function?

Devin Jeanpierre jeanpierreda at gmail.com
Thu Jan 19 10:56:00 EST 2012

```On Wed, Jan 18, 2012 at 6:20 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> On Wed, 18 Jan 2012 11:20:00 -0500, Devin Jeanpierre wrote:
> Nobody likes to be told to brush their teeth, eat their vegetables or
> clean their room. Then they grow up and learn that life is full of things
> that you do because you have to, not because you want to.

I don't tell my coworkers to brush their teeth, clean their room, and
eat their vegetables. You aren't his daddy.

Also, DBAD principle always applies. "I'm just telling you the truth"
is the defense of bullies. It's not about telling the truth, it's
about helping people. Or at least, I assume it is.

> That's just the way the zip operation works.

If you can't specifically explain it, who are you to tell others it's trivial?

> Because that's the nature of the Universe.

If I asked why 1*-1 has to be -1, and not 1, you could just say
"that's the nature of the universe", but that's just dodging the
question. Statements like these are theorems that can be proven. The
fact that they have been proven in the past does not magically make
them obvious. (You might think so now, but I distinctly remember a lot
of confusion in grade school when negative numbers were first
introduced. For me that confusion was never properly resolved until
much later.) The proof itself is the explanation, together with the
explanations for why the definitions make sense, and why each step in
the proof makes sense, recursively until the person who doesn't know
why this should be true is satisfied, or until the person is lost [in
which case, need to do something more bottom-up; you can't teach
somebody integration if they don't get multiplication]. If possible,
intuitive analogies should be used. (Math is specifically designed
around intuition as much as feasible.)

In the case of 1*-1 = -1, the explanation is that the definition of
"1" is that 1 * x = x, even if x is -1 [*] (this can be worded less
algebraically, since whoever asks you this is probably 7 years old).
Then one might ask, "well, why is that?", and then we must result to
the intuitive explanation of what "one" is, and how we extend that to
negative numbers (e.g. "take one step back" versus "one step forward";
"one backward step", etc.).

The point is that of _course_ it's the nature of the universe. Every
mathematical theorem follows from the definitions. That doesn't mean
it's simple, and that doesn't mean it can't be explained. As a matter
of fact it can be explained: I gave the explanation that made me "get
it". I'm sure there are other ways of wording the idea, but "that's
just the way the universe is" doesn't do anything for anyone except
make one confused person feel a little worse.

> The only complication is that you can't just pass the result of zip back
> to zip directly, you have to use the unpack operator * to split the
> result "one sequence of N subsequences" into N separate arguments.
>
> But apart from that complication, if you zip a bunch of sequences, then
> zip it again, you get back the original order. You describe that as
> taking the transpose of a matrix, which is correct, but that just puts a
> name to it, it doesn't explain *why* taking the transpose twice gives you
> the original matrix.

I did more than just say "nyer it's the transpose", I explained what a
transpose is and why it is that transpose is its own inverse. I think
you're right in thinking my explanation was too short, though.

Short version I already stated: the reason taking the transpose twice
results in the original matrix is because exchanges rows and columns
-- the columns of the transpose are the rows of the original.
Exchanging twice leaves you with the original (the comparison with
reverse is appropriate).

Call the transpose of A t(*A). Each row of t(*t(*A)) is a column of
t(*A), and each column of t(*A) is a row of A. so clearly every row of
t(*t(*A)) is a row of A. I assert that there are also the same number
of rows by the definition of the transpose (it only swaps, doesn't
delete), so t(*t(*A)) is the same as A! [All the rows are the same,
and there are the same number of rows <--> they are the same]

At this point I have to explain that t = zip. We could do this by
definition (ignoring that Python uses no such words), or we could do
this by explaining how the docs for zip describe transpose, or we
could say "compare it with transpose on several example matrices. The
second option turns out to pan out better than  expected: here is how
Python defines zip:

This function returns a list of tuples, where the i-th tuple
contains the i-th element from each of the argument sequences or
iterables.

This is how wikipedia defines the transpose:

Formally, the (i,j) element of A-Transpose is the (j,i) element of A.

Wikipedia adds the "j" to explain that the elements in the rows are in
the same order as the respective column in the original matrix. This
is also implied in the zip definition, but not made explicitly clear.
I assert that these are equivalent for matrices based on the above
based on perhaps a few manual experiments to verify that order is kept
by zip().

The only issue left now is that you can pass things that aren't
matrices into zip. zip has its own way of turning them into matrices,
which results in information being cut out -- specifically, if we have
a nested-sequence that doesn't really look like a rectangle (some rows
are longer than others), it cuts it short to force it into the shape
of a rectangle, treats this nested list as a matrix, returns the
transpose of the matrix. So zip(*x) is really only almost its own
inverse -- it's precisely its own inverse for matrices.

-- Devin

```