opposite of zip()?

Matt Nordhoff mnordhoff at mattnordhoff.com
Mon Dec 17 11:47:24 EST 2007


Rich Harkins wrote:
> igor.tatarinov at gmail.com wrote:
>> Given a bunch of arrays, if I want to create tuples, there is
>> zip(arrays). What if I want to do the opposite: break a tuple up and
>> append the values to given arrays:
>>    map(append, arrays, tupl)
>> except there is no unbound append() (List.append() does not exist,
>> right?).
>>
> 
> list.append does exist (try the lower-case flavor).
> 
>> Without append(), I am forced to write a (slow) explicit loop:
>>   for (a, v) in zip(arrays, tupl):
>>       a.append(v)
>>
> 
> Except that isn't technically the opposite of zip.  The opposite would
> be a tuple of single-dimensional tuples:
> 
> def unzip(zipped):
>     """
>     Given a sequence of size-sized sequences, produce a tuple of tuples
>     that represent each index within the zipped object.
> 
>     Example:
>     >>> zipped = zip((1, 2, 3), (4, 5, 6))
>     >>> zipped
>     [(1, 4), (2, 5), (3, 6)]
>     >>> unzip(zipped)
>     ((1, 2, 3), (4, 5, 6))
>     """
>     if len(zipped) < 1:
>         raise ValueError, 'At least one item is required for unzip.'
>     indices = range(len(zipped[0]))
>     return tuple(tuple(pair[index] for pair in zipped)
>                  for index in indices)
> 
> This is probably not the most efficient hunk of code for this but this
> would seem to be the correct behavior for the opposite of zip and it
> should scale well.
> 
> Modifying the above with list.extend would produce a variant closer to
> what I think you're asking for:
> 
> def unzip_extend(dests, zipped):
>     """
>     Appends the unzip versions of zipped into dests.  This avoids an
>     unnecessary allocation.
> 
>     Example:
>     >>> zipped = zip((1, 2, 3), (4, 5, 6))
>     >>> zipped
>     [(1, 4), (2, 5), (3, 6)]
>     >>> dests = [[], []]
>     >>> unzip_extend(dests, zipped)
>     >>> dests
>     [[1, 2, 3], [4, 5, 6]]
>     """
>     if len(zipped) < 1:
>         raise ValueError, 'At least one item is required for unzip.'
>     for index in range(len(zipped[0])):
>         dests[index].extend(pair[index] for pair in zipped)
> 
> This should perform pretty well, as extend with a comprehension is
> pretty fast.  Not that it's truly meaningful, here's timeit on my 2GHz
> laptop:
> 
> bash-3.1$ python -m timeit -s 'import unzip; zipped=zip(range(1024),
> range(1024))' 'unzip.unzip_extend([[], []], zipped)'
> 1000 loops, best of 3: 510 usec per loop
> 
> By comparison, here's the unzip() version above:
> 
> bash-3.1$ python -m timeit -s 'import unzip; zipped=zip(range(1024),
> range(1024))' 'unzip.unzip(zipped)'
> 1000 loops, best of 3: 504 usec per loop
> 
> Rich

As Paddy wrote, zip is its own unzip:

>>> zipped = zip((1, 2, 3), (4, 5, 6))
>>> zipped
[(1, 4), (2, 5), (3, 6)]
>>> unzipped = zip(*zipped)
>>> unzipped
[(1, 2, 3), (4, 5, 6)]

Neat and completely confusing, huh? :-)

<http://paddy3118.blogspot.com/2007/02/unzip-un-needed-in-python.html>
-- 



More information about the Python-list mailing list