Python:创建n个列表的最快方法


97

所以我想知道如何最好地创建空白列表的列表:

[[],[],[]...]

由于Python如何处理内存中的列表,因此不起作用:

[[]]*n

这确实会创建,[[],[],...]但是每个元素都是相同的列表:

d = [[]]*n
d[0].append(1)
#[[1],[1],...]

类似于列表理解的作品:

d = [[] for x in xrange(0,n)]

但这使用Python VM进行循环。有没有办法使用隐式循环(利用它用C编写)?

d = []
map(lambda n: d.append([]),xrange(0,10))

这实际上要慢一些。:(


1
如果有任何比这快得多的东西,我会感到惊讶d = [[] for x in xrange(0,n)]。您要么必须在Python中显式循环,要么重复调用Python函数/ lambda(这应该更慢)。但是仍然希望有人发布一些表明我错了的东西:)。
MAK

1
当您使用进行测量时timeit,您学到了什么?
S.Lott

我只是确认这map(lambda x: [], xrange(n))比列表理解要慢。
安德鲁·克拉克

Answers:


105

可能唯一的方法是比

d = [[] for x in xrange(n)]

from itertools import repeat
d = [[] for i in repeat(None, n)]

它不必int每次迭代都创建一个新对象,并且在我的计算机上快15%。

编辑:使用NumPy,可以避免使用Python循环

d = numpy.empty((n, 0)).tolist()

但这实际上比列表理解要慢2.5倍。


怎么map(lambda x:[], repeat(None,n))
PaulMcG 2011年

3
@Paul:由于lambda表达式的函数调用开销,这将再次变慢。
Sven Marnach 2011年

由于Python 3中的范围不同,现在不应该更新吗?
beruic

@beruic我只是在第一个代码块中引用问题中的代码,因此更改它实际上没有任何意义。
Sven Marnach

12

实际上,列表推导比显式循环更有效地实现(请参见示例功能dis输出),并且map每次迭代都必须调用不透明的可调用对象的方式,这会导致相当大的开销开销。

无论如何,[[] for _dummy in xrange(n)]这样做是正确的方法,其他各种方法之间的微小速度差异(如果存在的话)都不重要。当然,除非您花费大部分时间来执行此操作-但在那种情况下,您应该改为使用算法。您多久创建一次这些列表?


5
请不要_作为变量名!否则,一个很好的答案:)
Sven Marnach 2011年

11
@Sven:为什么不呢?它通常用于未使用的变量(如果称为i,我会寻找它的使用位置)。唯一的陷阱是,它遮蔽了_REPL中保持最后的结果……而这仅是2.x中列表推导泄漏的情况。

并不是很经常,这就是为什么我继续使用列表理解。以为看到人们不得不说些什么会很有趣。我在PyCon上看到了Dropbox的演讲,它使用了itertools.imap而不是for循环来大量更新md5哈希值,从那以后,我就一直沉迷于C循环。
munchybunch 2011年

12
不使用它的最重要原因是它会使人们感到困惑,使他们认为这是一种特殊的语法。并且除了与_交互式解释器中的冲突外,它还与通用的gettext别名冲突。如果您想弄清楚该变量是虚拟变量,请调用它dummy,而不是_
Sven Marnach 2011年

12

这是两种方法,一种是简单易用的(概念上的),另一种是较为正式的,可以在读取数据集后在各种情况下进行扩展。

方法1:概念

X2=[]
X1=[1,2,3]
X2.append(X1)
X3=[4,5,6]
X2.append(X3)
X2 thus has [[1,2,3],[4,5,6]] ie a list of lists. 

方法2:正式且可扩展

另一种优雅的方式将列表存储为不同编号的列表的列表-它是从文件中读取的。(这里的文件具有数据集train)Train是一个具有50行20列的数据集。即。Train [0]给我csv文件的第一行,train [1]给我第二行,依此类推。我有兴趣将50个行作为一个列表(第0列除外)分离为一个数据集,这是我在这里解释的变量,因此必须从原始火车数据集中删除,然后按列表放大列表(即列表的列表) 。这是执行此操作的代码。

请注意,由于我只对解释变量感兴趣,因此我正在读取内部循环中的“ 1”。我在另一个循环中重新初始化X1 = [],否则X2.append([0:(len(train [0])-1)])会一遍又一遍地重写X1-除此之外,它还提高了内存效率。

X2=[]
for j in range(0,len(train)):
    X1=[]
    for k in range(1,len(train[0])):
        txt2=train[j][k]
        X1.append(txt2)
    X2.append(X1[0:(len(train[0])-1)])

4

要创建列表和列表列表,请使用以下语法

     x = [[] for i in range(10)]

这将创建一维列表并将其初始化为[[number]中的放置数,并将列表长度设置为range(length)

  • 要创建列表列表,请使用以下语法。
    x = [[[0] for i in range(3)] for i in range(10)]

这将初始化尺寸为10 * 3且值为0的列表的列表

  • 访问/操作元素
    x[1][5]=value

2

所以我做了一些速度比较以获得最快的方法。列表理解确实非常快。接近的唯一方法是避免在构造列表期间执行字节码。我的第一个尝试是以下方法,该方法在原理上似乎更快:

l = [[]]
for _ in range(n): l.extend(map(list,l))

(当然,生成一个长度为2 ** n的列表)对于短列表和长列表(一百万个),根据时间的关系,此构造的速度是列表理解速度的两倍。

我的第二次尝试是使用starmap来为我调用列表构造函数,这是一种构造,它似乎以最快的速度运行列表构造函数,但仍然较慢,但数量很少:

from itertools import starmap
l = list(starmap(list,[()]*(1<<n)))

足够有趣的执行时间表明,最终列表调用使星图解决方案变慢,因为其执行时间几乎完全等于以下速度:

l = list([] for _ in range(1<<n))

当我意识到list(())也产生一个列表时,我进行了第三次尝试,因此我尝试了一种非常简单的方法:

l = list(map(list, [()]*(1<<n)))

但这比星图调用慢。

结论:对于速度狂:请使用列表理解。仅在需要时调用函数。使用内置函数。

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.