用列表输出而不是元组压缩


95

从两个列表中选择列表的最快,最优雅的方法是什么?

我有

In [1]: a=[1,2,3,4,5,6]

In [2]: b=[7,8,9,10,11,12]

In [3]: zip(a,b)
Out[3]: [(1, 7), (2, 8), (3, 9), (4, 10), (5, 11), (6, 12)]

我想要

In [3]: some_method(a,b)
Out[3]: [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

我当时在考虑使用map而不是zip,但我不知道是否有一些标准库方法作为第一个参数。

我可以为此定义自己的功能,并使用map,我的问题是是否已经实现了某些功能。也是答案。


1
好吧,您真的需要列表吗?您将如何处理结果?
Karl Knechtel '12

14
一个示例就是sklearn,其中许多次数据必须以这种方式进行组织。
tumultous_rooster 2013年

Answers:


103

如果您要压缩2个以上的列表(就此而言,甚至压缩2个),一种可读的方式将是:

[list(a) for a in zip([1,2,3], [4,5,6], [7,8,9])]

这使用列表推导并将列表(元组)中的每个元素转换为列表。


55

您自己几乎已经有了答案。不要使用map代替zip。使用map AND zip

您可以将地图和zip结合使用,以实现优雅,实用的方法:

list(map(list, zip(a, b)))

zip返回一个元组列表。map(list, [...])调用list列表中的每个元组。list(map([...])将地图对象变成可读列表。


让python 3集合操作返回一个不幸的决定是在这里generator加倍费用list
StephenBoesch

15

我喜欢zip函数的优雅,但是在operator模块中使用itemgetter()函数似乎要快得多。我写了一个简单的脚本来测试:

import time
from operator import itemgetter

list1 = list()
list2 = list()
origlist = list()
for i in range (1,5000000):
        t = (i, 2*i)
        origlist.append(t)

print "Using zip"
starttime = time.time()
list1, list2 = map(list, zip(*origlist))
elapsed = time.time()-starttime
print elapsed

print "Using itemgetter"
starttime = time.time()
list1 = map(itemgetter(0),origlist)
list2 = map(itemgetter(1),origlist)
elapsed = time.time()-starttime
print elapsed

我期望zip可以更快,但是itemgetter方法远胜于此:

Using zip
6.1550450325
Using itemgetter
0.768098831177

2
这是OP尝试执行的操作的转置。您可以更新您的帖子以反映这一点吗?即,OP正在将两个列表转换为列表或任意数量的对。您正在将任意数量的对转换为一对列表。
疯狂物理学家

该工具使用哪个python版本?
Moberg

我不记得是在两年前,但很可能是2.6或2.7。我想您可以复制代码并在自己的版本/平台上尝试。
kslnet

2
python 2zip创建一个真实列表。那会使事情变慢。尝试更换zipitertools.izip呢。
让·弗朗索瓦·法布尔

在Python 3.5中,zip需要3.5秒,itemgetter需要0.10秒。对于那些喜欢列表理解的人来说,list1 = [x[0] for x in origlist]效果和一样好list1 = map(itemgetter(0), origlist)
Elias Strehle,

3

我通常不喜欢使用lambda,但是...

>>> a = [1, 2, 3, 4, 5]
>>> b = [6, 7, 8, 9, 10]
>>> c = lambda a, b: [list(c) for c in zip(a, b)]
>>> c(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

如果您需要额外的速度,则地图会稍微快一些:

>>> d = lambda a, b: map(list, zip(a, b))
>>> d(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

但是,映射被认为是非Python的,仅应用于性能调整。


4
是什么lambda在这里补充?一个人可以只编写表达式而不是调用一个函数(这并不复杂),即使有人想要一个函数,也可以轻松地在两行中定义它(如果您的返回键已损坏或精神错乱,则可以定义为一行) 。map另一方面,如果第一个参数是普通函数(与相对lambda),则完全可以。

1
好吧,他要求一个功能。但是我同意-可能最好只是支付额外的费用。至于地图,我相信列表理解几乎总是很清晰。
Ceasar Bautista

1
我建议map结束lambda。这样map(list, zip(a,b))。列表理解可能会更清晰一些,但地图应该更快(未试用)
inspectorG4dget

我的意思是,再次强调,如果OP需要速度,则地图是必经之路。但是总的来说,尤其是在Python中,要着重于速度的可读性(否则您会陷入过早的优化)。
Ceasar Bautista

3

这个怎么样?

>>> def list_(*args): return list(args)

>>> map(list_, range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

甚至更好:

>>> def zip_(*args): return map(list_, *args)
>>> zip_(range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

在我看来,这是一个比其他方法更好的答案,因为在这里,我们不做zip而是直接创建列表,从而减少了一步。很棒
Akshay Hazari

2

使用numpy

优雅的定义可能会令人质疑,但是,如果您要numpy创建数组并将其转换为列表(如果需要...),则可能非常实用,即使使用map函数或列表理解相比效率不高。

import numpy as np 
a = b = range(10)
zipped = zip(a,b)
result = np.array(zipped).tolist()
Out: [[0, 0],
 [1, 1],
 [2, 2],
 [3, 3],
 [4, 4],
 [5, 5],
 [6, 6],
 [7, 7],
 [8, 8],
 [9, 9]]

否则跳过该zip功能,您可以直接使用np.dstack

np.dstack((a,b))[0].tolist()

1

我想列表理解将是非常简单的解决方案。

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

b=[7,8,9,10,11,12]

x = [[i, j] for i, j in zip(a,b)]

print(x)

output : [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.