How to convert list of tuples to multiple lists?
Question:
Suppose I have a list of tuples and I want to convert to multiple lists.
For example, the list of tuples is
[(1,2),(3,4),(5,6),]
Is there any built-in function in Python that convert it to:
[1,3,5],[2,4,6]
This can be a simple program. But I am just curious about the existence of such built-in function in Python.
Answers:
The built-in function zip()
will almost do what you want:
>>> list(zip(*[(1, 2), (3, 4), (5, 6)]))
[(1, 3, 5), (2, 4, 6)]
The only difference is that you get tuples instead of lists. You can convert them to lists using
list(map(list, zip(*[(1, 2), (3, 4), (5, 6)])))
From the python docs:
zip() in conjunction with the * operator can be used to unzip a list:
Specific example:
>>> zip((1,3,5),(2,4,6))
[(1, 2), (3, 4), (5, 6)]
>>> zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]
Or, if you really want lists:
>>> map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
[[1, 3, 5], [2, 4, 6]]
Use:
a = [(1,2),(3,4),(5,6),]
b = zip(*a)
>>> [(1, 3, 5), (2, 4, 6)]
Adding to Claudiu’s and Claudiu’s answer and since map needs to be imported from itertools in python 3, you also use a list comprehension like:
[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
Despite *zip
being more Pythonic, the following code has much better performance:
xs, ys = [], []
for x, y in zs:
xs.append(x)
ys.append(y)
Also, when the original list zs
is empty, *zip
will raise, but this code can properly handle.
I just ran a quick experiment, and here is the result:
Using *zip: 1.54701614s
Using append: 0.52687597s
Running it multiple times, append
is 3x – 4x faster than zip
! The test script is here:
#!/usr/bin/env python3
import time
N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(zip(xs, ys))
t1 = time.time()
xs_, ys_ = zip(*zs)
print(len(xs_), len(ys_))
t2 = time.time()
xs_, ys_ = [], []
for x, y in zs:
xs_.append(x)
ys_.append(y)
print(len(xs_), len(ys_))
t3 = time.time()
print('Using *zip:t{:.8f}s'.format(t2 - t1))
print('Using append:t{:.8f}s'.format(t3 - t2))
My Python Version:
Python 3.6.3 (default, Oct 24 2017, 12:18:40)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
franklsf95 goes for performance in his answer and opts for list.append()
, but they are not optimal.
Adding list comprehensions, I ended up with the following:
def t1(zs):
xs, ys = zip(*zs)
return xs, ys
def t2(zs):
xs, ys = [], []
for x, y in zs:
xs.append(x)
ys.append(y)
return xs, ys
def t3(zs):
xs, ys = [x for x, y in zs], [y for x, y in zs]
return xs, ys
if __name__ == '__main__':
from timeit import timeit
setup_string='''
N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(zip(xs, ys))
from __main__ import t1, t2, t3
'''
print(f'zip:tt{timeit('t1(zs)', setup=setup_string, number=1000)}')
print(f'append:tt{timeit('t2(zs)', setup=setup_string, number=1000)}')
print(f'list comp:t{timeit('t3(zs)', setup=setup_string, number=1000)}')
This gave the result:
zip: 122.11585397789766
append: 356.44876132614047
list comp: 144.637765085659
So if you are after performance, you should probably use zip()
although list comprehensions are not too far behind. The performance of append
is actually pretty poor in comparison.
In addition to Claudiu’s answer, you can use:
>>>a, b = map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
>>>a
[1,3,5]
>>>b
[2,4,6]
Edited according to @Peyman mohseni kiasari
Suppose I have a list of tuples and I want to convert to multiple lists.
For example, the list of tuples is
[(1,2),(3,4),(5,6),]
Is there any built-in function in Python that convert it to:
[1,3,5],[2,4,6]
This can be a simple program. But I am just curious about the existence of such built-in function in Python.
The built-in function zip()
will almost do what you want:
>>> list(zip(*[(1, 2), (3, 4), (5, 6)]))
[(1, 3, 5), (2, 4, 6)]
The only difference is that you get tuples instead of lists. You can convert them to lists using
list(map(list, zip(*[(1, 2), (3, 4), (5, 6)])))
From the python docs:
zip() in conjunction with the * operator can be used to unzip a list:
Specific example:
>>> zip((1,3,5),(2,4,6))
[(1, 2), (3, 4), (5, 6)]
>>> zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]
Or, if you really want lists:
>>> map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
[[1, 3, 5], [2, 4, 6]]
Use:
a = [(1,2),(3,4),(5,6),]
b = zip(*a)
>>> [(1, 3, 5), (2, 4, 6)]
Adding to Claudiu’s and Claudiu’s answer and since map needs to be imported from itertools in python 3, you also use a list comprehension like:
[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
Despite *zip
being more Pythonic, the following code has much better performance:
xs, ys = [], []
for x, y in zs:
xs.append(x)
ys.append(y)
Also, when the original list zs
is empty, *zip
will raise, but this code can properly handle.
I just ran a quick experiment, and here is the result:
Using *zip: 1.54701614s
Using append: 0.52687597s
Running it multiple times, append
is 3x – 4x faster than zip
! The test script is here:
#!/usr/bin/env python3
import time
N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(zip(xs, ys))
t1 = time.time()
xs_, ys_ = zip(*zs)
print(len(xs_), len(ys_))
t2 = time.time()
xs_, ys_ = [], []
for x, y in zs:
xs_.append(x)
ys_.append(y)
print(len(xs_), len(ys_))
t3 = time.time()
print('Using *zip:t{:.8f}s'.format(t2 - t1))
print('Using append:t{:.8f}s'.format(t3 - t2))
My Python Version:
Python 3.6.3 (default, Oct 24 2017, 12:18:40)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
franklsf95 goes for performance in his answer and opts for list.append()
, but they are not optimal.
Adding list comprehensions, I ended up with the following:
def t1(zs):
xs, ys = zip(*zs)
return xs, ys
def t2(zs):
xs, ys = [], []
for x, y in zs:
xs.append(x)
ys.append(y)
return xs, ys
def t3(zs):
xs, ys = [x for x, y in zs], [y for x, y in zs]
return xs, ys
if __name__ == '__main__':
from timeit import timeit
setup_string='''
N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(zip(xs, ys))
from __main__ import t1, t2, t3
'''
print(f'zip:tt{timeit('t1(zs)', setup=setup_string, number=1000)}')
print(f'append:tt{timeit('t2(zs)', setup=setup_string, number=1000)}')
print(f'list comp:t{timeit('t3(zs)', setup=setup_string, number=1000)}')
This gave the result:
zip: 122.11585397789766
append: 356.44876132614047
list comp: 144.637765085659
So if you are after performance, you should probably use zip()
although list comprehensions are not too far behind. The performance of append
is actually pretty poor in comparison.
In addition to Claudiu’s answer, you can use:
>>>a, b = map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
>>>a
[1,3,5]
>>>b
[2,4,6]
Edited according to @Peyman mohseni kiasari