【发布时间】:2011-12-26 06:18:07
【问题描述】:
假设我有一个元组列表,我想转换为多个列表。
例如,元组的列表是
[(1,2),(3,4),(5,6),]
Python中是否有任何内置函数可以将其转换为:
[1,3,5],[2,4,6]
这可以是一个简单的程序。但是我只是对Python中存在这样的内置函数感到好奇。
【问题讨论】:
假设我有一个元组列表,我想转换为多个列表。
例如,元组的列表是
[(1,2),(3,4),(5,6),]
Python中是否有任何内置函数可以将其转换为:
[1,3,5],[2,4,6]
这可以是一个简单的程序。但是我只是对Python中存在这样的内置函数感到好奇。
【问题讨论】:
内置函数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)])))
【讨论】:
list(zip(*[(1, 2), (3, 4), (5, 6)])).
zip() 和 map() 返回列表,而不是像在 Python 3 中那样的惰性迭代器。我会更新答案。
来自python docs:
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),]
b = zip(*a)
>>> [(1, 3, 5), (2, 4, 6)]
【讨论】:
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 的表现其实很差。
【讨论】:
尽管*zip 更加Pythonic,但以下代码具有更好的性能:
xs, ys = [], []
for x, y in zs:
xs.append(x)
ys.append(y)
另外,当原始列表zs 为空时,*zip 会引发,但这段代码可以正常处理。
我刚刚做了一个快速实验,结果如下:
Using *zip: 1.54701614s
Using append: 0.52687597s
多次运行,append 比 zip 快 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.
【讨论】:
除了克劳迪乌的回答,你还可以使用:
>>>a, b = map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
>>>a
[1,3,5]
>>>b
[2,4,6]
根据@Peyman mohseni kiasari 编辑
【讨论】:
(1, 3, 5) 和(2, 4, 6) 而不是列表。你应该使用map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
添加到 Claudiu 和 Claudiu 的答案,并且由于 map 需要从 python 3 中的 itertools 导入,您还可以使用如下列表理解:
[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
【讨论】: