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

112 投票
5 回答
219534 浏览
提问于 2025-04-16 14:55

我在想怎么最好地创建一个空列表的列表:

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

因为Python处理内存中的列表的方式,这种方法是行不通的:

[[]]*n

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

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

像列表推导式这样的方式是可以的:

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

但是这会使用Python虚拟机来循环。有没有办法利用隐式循环(因为它是用C语言写的)呢?

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

其实这样做会更慢。 :(

5 个回答

12

这里有两种方法,一种简单易懂(概念性),另一种更正式,可以在多种情况下使用,都是在读取数据集之后的。

方法一:概念性

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. 

方法二:正式且可扩展

另一种优雅的方式是将一个列表存储为不同数字的列表的列表——这个列表是从一个文件中读取的。(这里的文件包含数据集 train)

Train 是一个数据集,假设有 50 行和 20 列。也就是说,Train[0] 给我的是 CSV 文件的第一行,train[1] 给我的是第二行,以此类推。我想把这 50 行的数据集分成一个列表,除了第 0 列,因为那是我这里要解释的变量,所以必须从原始的 train 数据集中去掉,然后把每一行的列表一个接一个地放在一起——也就是一个列表的列表。下面是实现这个功能的代码。

注意,我在内层循环中从 "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)])
12

列表推导式的实现其实比用显式循环要高效得多(你可以查看这个例子中dis的输出)。而使用map的方式在每次循环时都需要调用一个不透明的可调用对象,这样会带来相当大的开销。

不管怎样,[[] for _dummy in xrange(n)]是正确的做法,其他一些方法之间的微小(如果有的话)速度差异其实并不重要。除非你大部分时间都在做这个——但如果是这样的话,你应该先优化你的算法。你多久会创建一次这些列表呢?

117

可能唯一一种比

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

稍微快一点的方法是

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

这样做的好处是,它在每次循环时不需要创建一个新的 int 对象,所以在我的机器上大约快了15%。

补充说明:如果使用NumPy,你可以通过

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

来避免使用Python的循环,但实际上这比列表推导式慢了2.5倍。

撰写回答