Fastest way to make a list-like object containing integers in python
这意味着我希望有一个对象支持列表的两个(非常)基本操作:获取某个索引(1)中的对象并更改其值(2)。
在发布这个之前我遇到了什么帖子?为什么他们没有解决我的问题?我遇到了这两个[1][2]
他们没有解决我的问题,因为他们的所有解决方案都太慢了:在我的电脑中,
我试过使用
1 2 | from ctypes import c_int array = (c_int * 10 ** 8)() |
上面的代码只花了0.7秒…但是有没有办法让它更快呢?除了速度快之外,它还有一些缺点:
真的可以按我的要求去做吗?有没有比使用
我正在使用Python进行有竞争力的编程,大多数解释器/评委都不允许使用外部库。
我们可以用array.array存储自定义对象吗?我可以看到许多答案使用了
1 2 3 4 5 6 7 8 | class Point: def __init__(self, x, y): self.x = x self.y = y # make array.array object with all indexes containing a Point with atributes x and y with value 0 # an example with a list of what I want to do is this: # l = [Point(0, 0) for _ in range(10**3)] |
array.array('i',(0,) * 10**8) resulted in an error (lol)
您没有指定您得到了什么错误-这对我很有效,尽管它不是很快,因为它构建了一个中间元组并立即丢弃它。使用python的内置类型,如果避免使用tuple:
1 | a = array.array('i', (0,)) * 10**8 |
The code above took only 0.7 seconds ... but is there a way to make it faster?
如果不允许创建或导入C扩展,那么很难击败
1 2 | # 0.22 s a = array.array('i', (0,) * 10) * 10**7 |
在我的计算机上,以下版本最有效:
1 2 | # 0.19 s a = array.array('i', (0,) * 100) * 10**6 |
进一步增加初始阵列大小没有帮助,很快就会开始降低性能。
为了获得更好的效率,请考虑其他方法,例如一个懒惰的列表或为您的用例定制的完全不同的数据结构。考虑到竞争的背景,这可能正是人们真正想要的。
但是,请注意,每个解决方案都会有不同的权衡。例如,@konstantinnikitin提供的一个延迟数组构造起来非常有效,但是它的
我只使用支持快速阵列操作的
例如,用数字0到10**8创建一个数组:
1 2 3 4 5 6 7 8 | import numpy as np import time b = time.time() a = np.linspace(0, 10**8, 10**8) c = time.time() print(c-b) >>>0.5000154972076416 |
或者制作一个10*8长的0数组:
1 2 3 4 5 | b = time.time() a = np.zeros(shape=(10**8,)) c = time.time() print(c-b) >>>0.0 |
numpy如此之快的主要原因是它是在C中实现的。
编辑:如果只想使用预安装的软件包,可以尝试使用
1 2 3 4 5 6 | import array import time r = time.time() a = array.array('i', [0]) * (10**8) print(time.time()-r) >>>0.15627217292785645 |
如果您只想要这两个属性:
getting an object in a certain index (1) and changing its value (2)
那么你只需使用一个
1 2 | import collections my_list = collections.defaultdict(lambda: 0) |
相当快(~0.4μs):
1 2 | $ python3 -m timeit -s 'import collections' 'collections.defaultdict(lambda: 0)' 1000000 loops, best of 3: 0.417 usec per loop |
然而,实际使用它可能会比其他答案中建议的任何类型慢很多。
我想说你可以尝试不同的方法:
1)
1 2 3 4 | x = numpy.array(10 ** 8) timeit.timeit('x = numpy.array(10 ** 8)', 'import numpy', number=1) 4.195800283923745e-05 |
2)延迟初始化(如javascript数组)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class LazyArray: def __init__(self, size): self.storage = {} self.size = size def check(self, i): if i < 0 or i >= self.size: raise RuntimeError() def __getitem__(self, i): self.check(i) return self.storage.get(i, 0) def __setitem__(self, i, value): self.check(i) self.storage[i] = value x = LazyArray(10 ** 8) x[10] >> 0 x[10] = 5 x[10] >> 0 |
对于只需要0到255之间的整数的情况,
1 2 3 4 5 6 | >>> timeit.timeit('bytearray(100000)', number=1000) 0.005567271093696036 >>> timeit.timeit('array.array("B", [0])*100000', 'import array', number=1000) 0.36631167401839093 >>> timeit.timeit('array.array("i", [0])*100000', 'import array', number=1000) 0.56494557472422 |
与