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

Posted

技术标签:

【中文标题】使用列表输出而不是元组进行压缩【英文标题】:Zip with list output instead of tuple 【发布时间】:2012-01-12 10:20:43 【问题描述】:

从两个列表中列出列表的最快和最优雅的方法是什么?

我有

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,但我不知道是否有一些标准库方法可以作为第一个参数。

我可以为此定义自己的函数,并使用地图,我的问题是是否已经实现了某些东西。 也是一个答案。

【问题讨论】:

那么,您真的需要列表吗?你打算如何处理结果? 一个例子是 sklearn,很多时候数据必须以这种方式组织。 【参考方案1】:

我一般不喜欢使用 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]]

但是,map 被认为是非 Python 的,只能用于性能调整。

【讨论】:

lambda 在这里添加了什么?一个人可以只写表达式而不是调用一个函数(它真的不复杂),即使你想要一个函数,它也可以用两行轻松定义(如果你的返回键坏了或者你疯了) .另一方面,map 非常好,如果第一个参数是一个普通函数(而不是 lambda)。 好吧,他要求一个函数。但我同意 - 最好只支付额外的费用。至于地图,我相信列表理解几乎总是更清晰。 我会推荐map 而不是lambda。所以map(list, zip(a,b))。列表推导可能更清晰一些,但 map 应该更快(未经测试) 我的意思是,再次,如果 OP 需要速度,map 是要走的路。但总的来说,尤其是在 Python 中,强调可读性而不是速度(否则你会陷入过早的优化)。【参考方案2】:

如果您要压缩 2 个以上的列表(或者甚至只有 2 个),那么一种可读的方式是:

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

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

【讨论】:

【参考方案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]]

【讨论】:

在我看来,这似乎是一个比其他答案更好的答案,因为在这里我们通过不进行压缩并直接创建列表来减少一步。太棒了【参考方案4】:

我喜欢 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

【讨论】:

这是对 OP 试图做的事情的转置。您能否更新您的帖子以反映这一点?即,OP 正在将两个列表转换为列表或任意数量的对。您正在将任意数量的对转换为一对列表。 这是用哪个 python 版本测量的? 我不记得了,两年多以前了,但很可能是 2.6 或 2.7。我想您可以复制代码并在您自己的版本/平台上尝试。 python 2 zip 创建一个真实的列表。这会减慢速度。然后尝试将zip 替换为itertools.izip 在 Python 3.5 中,zip 需要 3.5 秒,而 itemgetter 需要 0.10 秒。对于那些喜欢列表推导的人,list1 = [x[0] for x in origlist]list1 = map(itemgetter(0), origlist) 一样好用。【参考方案5】:

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

您可以将 map 与 zip 一起使用,以获得优雅、实用的方法:

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

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

【讨论】:

让 python 3 集合操作返回 generator 的不幸决定在这里强加了双倍 list 的成本。【参考方案6】:

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

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

【讨论】:

【参考方案7】:

使用 numpy

优雅的定义可能非常值得怀疑,但如果您正在使用numpy,则创建数组并将其转换为列表(如果需要...)可能非常实用,尽管与使用map 函数或列表推导。

import numpy as np 
a = b = range(10)
zipped = zip(a,b)
# result = np.array(zipped).tolist() Python 2.7
result = np.array(list(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()

【讨论】:

第一个例子对我不起作用,np.array(zipped) 是一个array(<class 'zip'>, dtype=object),把它放到一个列表中只返回一个zip 不过np.array(list(zipped)).tolist() 会起作用 @JeanBouvattier 感谢您的评论,是的,这是因为在 Python 3 中 zip 不再是一个列表而是一个 zip 对象

以上是关于使用列表输出而不是元组进行压缩的主要内容,如果未能解决你的问题,请参考以下文章

为啥解包在 Python 中给出一个列表而不是一个元组?

如何使用 OCaml 将两个列表中的每个单独元素压缩到一个列表中

使用不在模型中的字段扩展 django 表单,导致错误,只能连接列表,而不是元组

Django 错误遵循教程 b/c 使用 3.1 而不是 1.9 TypeError:在 include() 的情况下,视图必须是可调用的或列表/元组 [重复]

itertools.product - 返回列表而不是元组

从文本文件中读取列表元组作为元组,而不是字符串 - Python