开发者

How to preallocate a list of lists?

I am creating a list of lists using this code:

zeroArray = [0]*Np
zeroMat开发者_运维问答rix = []
for i in range(Np):
    zeroMatrix.append(zeroArray[:])

Is there a more efficient way to do this? I'm hoping for something along the lines of zeroArray = [0]*Np; zeroMat = zeroArray*Np but can't find anything similar.


Maybe you should consider using NumPy. It seems like you're doing numerical work, which is what it's made for. This is the fastest so far, not including the import statement:

import numpy
Np = 80
zeroMatrix = numpy.zeros((Np, Np))

Times:

>python -m timeit -s "import numpy; Np = 80" "zeroMatrix = numpy.zeros((Np, Np))"
100000 loops, best of 3: 4.36 usec per loop

>python -m timeit -s "Np = 80" "zeroArray = [0]*Np" "zeroMatrix = [None] * Np" "for i in range(Np):" "  zeroMatrix[i] = zeroArray[:]"
10000 loops, best of 3: 62.5 usec per loop

>python -m timeit -s "Np = 80" "zeroMatrix = [[0] * Np for i in range (Np)]"
10000 loops, best of 3: 77.5 usec per loop

>python -m timeit -s "Np = 80" "zeroMatrix = [[0 for _ in range(Np)] for _ in range(Np)]"
1000 loops, best of 3: 474 usec per loop


You could do this:

zeroMatrix = [[0] * Np for i in range(Np)]

Update: Well if we're going to make it into a race, I've found something faster (on my computer) than Omnifarious' method. This doesn't beat numpy of course; but this is all academic anyway right? I mean we're talking about microseconds here.

I think this works because it avoids append and avoids preallocating zeroMatrix.

zeroArray = [0] * Np
zeroMatrix = [zeroArray[:] for i in range(Np)]

My test results:

$ python -m timeit -s "Np = 80" "zeroMatrix = [[0] * Np for i in range(Np)]"
1000 loops, best of 3: 200 usec per loop
$ python -m timeit -s "Np = 80" "zeroArray = [0] * Np" "zeroMatrix = [None] * Np" "for i in range(Np):" "    zeroMatrix[i] = zeroArray[:]"
10000 loops, best of 3: 171 usec per loop
$ python -m timeit -s "Np = 80" "zeroArray = [0] * Np" "zeroMatrix = [zeroArray[:] for i in range(Np)]"
10000 loops, best of 3: 165 usec per loop


This would probably be slightly more efficient:

zeroArray = [0]*Np
zeroMatrix = [None] * Np
for i in range(Np):
    zeroMatrix[i] = zeroArray[:]

What you would really like won't work the way you hope. This is because if you created Np copies of a list element using *, you get Np references to the same thing. For the 0 this isn't a big deal since you just get a new number when you add anything to it. But for lists you would end up with a matrix where as soon as you changed any element of a row, the entire column would change right along with it.

This way is the second fastest so far mentioned:

$ python3 -m timeit -s 'Np = 80' 'zeroArray = [0]*Np
zeroMatrix = [None] * Np
for i in range(Np):
    zeroMatrix[i] = zeroArray[:]'
10000 loops, best of 3: 72.8 usec per loop

$ python3 -m timeit -s 'Np = 80' 'zeroMatrix = [[0] * Np for i in range(Np)]'
10000 loops, best of 3: 85 usec per loop

$ python3 -m timeit -s 'Np = 80' 'zeroMatrix = [[0 for _ in range(Np)] for _ in range(Np)]'
1000 loops, best of 3: 566 usec per loop

I can't do my own timeit of the numpy-based solution as I don't have a numpy package for Python3 on my system. But it is very definitely faster by a significant margin.


Perhaps this is what you'd like?

zeroMatrix = [[0 for _ in range(Np)] for _ in range(Np)]

I'm not sure if this will provide a performance benefit (profile, as always) but I don't really know what you mean by "efficient." Other than avoiding the use of list.append.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜