Initializing a list to a known number of elements in Python
现在,我正在使用一个列表,并期望如下:
1 | verts = list (1000) |
我应该改用数组吗?
我首先想到的是:
1 | verts = [None]*1000 |
但您真的需要预初始化它吗?
不太清楚为什么每个人都让你很难做到这一点——有几种情况下你需要一个固定大小的初始化列表。您已经正确地推断出数组在这些情况下是合理的。
1 2 | import array verts=array.array('i',(0,)*1000) |
对于非pythonistas,
我使用了元组而不是列表,因为它们的开销通常较低。
一个明显的而且可能不有效的方法是
1 | verts = [0 for x in range(1000)] |
注意,这可以很容易地扩展到二维。例如,要获得一个10x100"阵列",您可以这样做
1 | verts = [[0 for x in range(100)] for y in range(10)] |
在任何编程语言中,想要初始化一个固定大小的数组是完全可以接受的事情;这不像程序员想要在while(true)循环中放入break语句。相信我,尤其是如果元素只是要被覆盖,而不仅仅是加/减,就像许多动态编程算法一样,你不想乱弄APPEND语句,检查元素是否还没有被动态初始化(这是很多代码代理)。
这将适用于程序员试图实现的目标。
@史蒂夫已经给了你一个很好的答案:
1 | verts = [None] * 1000 |
警告:正如@joachim wutke指出的,列表必须用不可变元素初始化。
调整列表大小很慢。以下结果并不令人惊讶:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> N = 10**6 >>> %timeit a = [None] * N 100 loops, best of 3: 7.41 ms per loop >>> %timeit a = [None for x in xrange(N)] 10 loops, best of 3: 30 ms per loop >>> %timeit a = [None for x in range(N)] 10 loops, best of 3: 67.7 ms per loop >>> a = [] >>> %timeit for x in xrange(N): a.append(None) 10 loops, best of 3: 85.6 ms per loop |
但是,如果没有非常大的列表,那么调整大小不是很慢。不要用单个元素(如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> %timeit a = [x**2 for x in xrange(N)] 10 loops, best of 3: 109 ms per loop >>> def fill_list1(): """Not too bad, but complicated code""" a = [None] * N for x in xrange(N): a[x] = x**2 >>> %timeit fill_list1() 10 loops, best of 3: 126 ms per loop >>> def fill_list2(): """This is slow, use only for small lists""" a = [] for x in xrange(N): a.append(x**2) >>> %timeit fill_list2() 10 loops, best of 3: 177 ms per loop |
与numpy比较
对于大型数据集,numpy或其他优化的库速度更快:
1 2 3 4 5 6 | from numpy import ndarray, zeros %timeit empty((N,)) 1000000 loops, best of 3: 788 ns per loop %timeit zeros((N,)) 100 loops, best of 3: 3.56 ms per loop |
你可以这样做:
1 | verts = list(xrange(1000)) |
这将给您一个1000个元素的大小列表,并且恰好用0-999之间的值初始化。正如
这是:
1 | lst = [8 for i in range(9)] |
创建列表,初始化元素8
但这:
1 | lst = [0] * 7 |
将创建7个具有一个元素的列表
您应该考虑使用
当使用映射时,您可以编写:
1 2 3 | aDict = {} aDict[100] = fetchElement() putElement(fetchElement(), fetchPosition(), aDict) |
1 2 | if anIndex in aDict: print"cool!" |
比:
1 2 | if not myList[anIndex] is None: print"cool!" |
因为后者假定集合中没有真正的元素可以是
如果你非常需要性能,这就是为什么你要尝试预先初始化变量,并尽可能快地编写代码——改变你的语言。最快的代码不能用Python编写。您应该改为尝试c并实现包装器来从python调用预初始化和预编译的代码。
如果不了解问题领域的更多信息,很难回答您的问题。除非您确定需要做更多的事情,否则初始化列表的方法是:
1 | verts = [] |
你真的看到性能问题了吗?如果是,那么性能瓶颈是什么?不要试图解决你没有的问题。动态地将数组填充到1000个元素中的性能成本很可能与您真正想要编写的程序完全无关。
如果列表中的内容总是特定的基元固定长度类型(例如char、int、float),则array类非常有用。但是,它也不需要预初始化。