如何将元组列表转换为多个列表?

假设我有一个元组列表,我想转换成多个列表。

例如,元组列表是

[(1,2),(3,4),(5,6),]

Python 中是否有内置函数将其转换为:

[1,3,5],[2,4,6]

这可以是一个简单的程序,但是我只是好奇 Python 中是否存在这样的内置函数。

84994 次浏览

内置的函数 zip()几乎可以满足您的需要:

>>> list(zip(*[(1, 2), (3, 4), (5, 6)]))
[(1, 3, 5), (2, 4, 6)]

唯一的区别是您得到的是元组而不是列表

list(map(list, zip(*[(1, 2), (3, 4), (5, 6)])))

来自 巨蟒文档:

Zip ()和 * 操作符可以用来解压缩列表:

具体例子:

>>> 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)]

或者,如果你真的想要列表:

>>> map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
[[1, 3, 5], [2, 4, 6]]
>>> a = [(1,2),(3,4),(5,6),]
>>> zip(*a)
[(1, 3, 5), (2, 4, 6)]

添加到 Claudiu 和 Claudiu 的回答中,并且因为 map 需要从 python 3中的 itertools 导入,所以您还可以使用一个列表内涵,比如:

[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]

尽管 *zip更加 Python 化,但是下面的代码有更好的性能:

xs, ys = [], []
for x, y in zs:
xs.append(x)
ys.append(y)

此外,当原始列表 zs为空时,*zip将引发,但此代码可以正确处理。

我做了个小实验,结果是这样的:

Using *zip:     1.54701614s
Using append:   0.52687597s

运行多次,appendzip快3-4倍! 测试脚本如下:

#!/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))

返回文章页面我的 Python 译者:

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在他的回答中考虑了性能,选择了 list.append(),但它们并不是最优的。

在添加了列表理解之后,我得出了以下结论:

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:\t\t{timeit('t1(zs)', setup=setup_string, number=1000)}')
print(f'append:\t\t{timeit('t2(zs)', setup=setup_string, number=1000)}')
print(f'list comp:\t{timeit('t3(zs)', setup=setup_string, number=1000)}')

结果是:

zip:            122.11585397789766
append:         356.44876132614047
list comp:      144.637765085659

因此,如果您是在性能之后,您可能应该使用 zip(),尽管列表理解并不太落后。相比之下,append的性能实际上相当差。

除了克劳迪奥的回答,你还可以用:

>>>a, b = map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
>>>a
[1,3,5]
>>>b
[2,4,6]

编辑:@Peyman mohseni kiasari