Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting a list of sequences into two lists efficiently [duplicate]

Possible Duplicate:
A Transpose/Unzip Function in Python

I have a list of sequences, each sequence has two items. I would like to turn this into two lists.

catalog = [('abc', '123'), ('foo', '456'), ('bar', '789'), ('test', '1337')]

Right now I'm just doing this:

names = []
vals = []

for product in catalog:
        names.append(product[0])
        vals.append(product[1])

print (names)
print (vals)

Which outputs two lists, and works just fine:

['abc', 'foo', 'bar', 'test']
['123', '456', '789', '1337']

Is there a neater, more 'pythonic' way of doing this? Or should I stick with what I have? Any corrections or feedback on programming style is welcome, I'm new and trying to learn best practices.

like image 268
Ryan Rapini Avatar asked Dec 17 '12 18:12

Ryan Rapini


People also ask

Can you split () a list in Python?

Python String split() MethodThe split() method splits a string into a list. You can specify the separator, default separator is any whitespace. Note: When maxsplit is specified, the list will contain the specified number of elements plus one.

How do you split an array into two parts in Python?

Use the array_split() method, pass in the array you want to split and the number of splits you want to do.


2 Answers

>>> catalog = [('abc', '123'), ('foo', '456'), ('bar', '789'), ('test', '1337')]
>>> names, vals = zip(*catalog)
>>> names
('abc', 'foo', 'bar', 'test')
>>> vals
('123', '456', '789', '1337')

The *catalog syntax here is called Unpacking Argument Lists, and zip(*catalog) translates into the call zip(catalog[0], catalog[1], catalog[2], ...).

The zip() builtin function groups iterables by indices, so when you pass a bunch of two-element tuples as above, you get a two-element list of tuples where the first tuple contains the first element of each tuple from catalog, and the second tuple contains the second element from each tuple from catalog.

In a quick timeit test the zip() version outperforms a looping approach when I tested with 1,000,000 pairs:

In [1]: catalog = [(i, i+1) for i in range(1000000)]

In [2]: def with_zip():
   ...:     return zip(*catalog)
   ...: 

In [3]: def without_zip():
   ...:     names, vals = [], []
   ...:     for name, val in catalog:
   ...:         names.append(name)
   ...:         vals.append(val)
   ...:     return names, vals
   ...: 

In [4]: %timeit with_zip()
1 loops, best of 3: 176 ms per loop

In [5]: %timeit without_zip()
1 loops, best of 3: 250 ms per loop
like image 70
Andrew Clark Avatar answered Oct 22 '22 03:10

Andrew Clark


Sure, use this:

lst = [('abc', '123'), ('foo', '456'), ('bar', '789'), ('test', '1337')]
tup1, tup2 = zip(*lst)

The above will return a pair of tuples with the elements. If you need lists, then use this:

lst = [('abc', '123'), ('foo', '456'), ('bar', '789'), ('test', '1337')]
lst1, lst2 = map(list, zip(*lst))
like image 36
Óscar López Avatar answered Oct 22 '22 04:10

Óscar López