在python中创建包含整数的类似列表的对象的最快方法 在python中创建包含整数/浮点数(非常简单的数据类型)的列表状对象的最快方法是什么? 我所说的“类似列表”是什么意思?
这意味着我希望有一个对象支持列表的两个(非常)基本操作:获取某个索引中的对象(1)和更改其值(2) 在发布这篇文章之前,我遇到了哪些帖子,为什么它们没有解决我的问题? 我遇到了这两个:在python中创建包含整数的类似列表的对象的最快方法 在python中创建包含整数/浮点数(非常简单的数据类型)的列表状对象的最快方法是什么? 我所说的“类似列表”是什么意思?,python,list,Python,List,这意味着我希望有一个对象支持列表的两个(非常)基本操作:获取某个索引中的对象(1)和更改其值(2) 在发布这篇文章之前,我遇到了哪些帖子,为什么它们没有解决我的问题? 我遇到了这两个: 他们没有解决我的问题,因为他们的所有解决方案都太慢了:在我的电脑中array。array('i',(0,)*10**8)导致了一个错误(lol)[0表示范围内(10**8)]花费了大约15秒(哇!)[0]*10**8耗时2.3秒[无]*10**8耗时1.8秒;(1.8秒可能更快…) 我试着做什么? 我尝试使用c
他们没有解决我的问题,因为他们的所有解决方案都太慢了:在我的电脑中
array。array('i',(0,)*10**8)
导致了一个错误(lol)<代码>[0表示范围内(10**8)]花费了大约15秒(哇!)<代码>[0]*10**8耗时2.3秒<代码>[无]*10**8耗时1.8秒;(1.8秒可能更快…)
我试着做什么?
我尝试使用ctypes
模块
from ctypes import c_int
array = (c_int * 10 ** 8)()
上面的代码只用了0.7秒。。。但是有没有办法让它更快呢?除了速度快之外,它还有一些缺点:
ctypes
模块更快的方法?如果是,请确保您使用的是“内置”/“预装”模块
编辑:
为什么我不能简单地安装一些模块,比如numpy?
我使用python进行竞争性编程,大多数解释器/评判员都不允许使用外部库
我们可以用array.array存储自定义对象吗?
我可以看到许多答案都使用了array
模块的array
功能。它们都使用“i”来指定我们要存储的整数。可以创建一个类并创建一个包含它的“array.array”吗?例如:
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)]
我只想使用
numpy
模块,它支持快速数组操作
例如,制作一个数字为0到10**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数组:
b = time.time()
a = np.zeros(shape=(10**8,))
c = time.time()
print(c-b)
>>>0.0
numpy之所以这么快,主要是因为它是用C实现的
编辑:
如果只想使用预装的软件包,可以尝试使用array
软件包:
import array
import time
r = time.time()
a = array.array('i', [0]) * (10**8)
print(time.time()-r)
>>>0.15627217292785645
我想说,你可以尝试不同的方法: 1)
numpy
。它实际上是阵列的标准。每个操作都需要跨越Python C边界,但这实际上取决于您的任务
x = numpy.array(10 ** 8)
timeit.timeit('x = numpy.array(10 ** 8)', 'import numpy', number=1)
4.195800283923745e-05
2) 延迟初始化(如JavaScript数组)
class LazyArray:
定义初始值(自身,大小):
self.storage={}
self.size=大小
def检查(自我,i):
如果i<0或i>=self.size:
引发运行时错误()
定义获取项目(自我,i):
自我检查(一)
返回self.storage.get(i,0)
定义设置项(自身、i、值):
自我检查(一)
自存储[i]=值
x=LazyArray(10**8)
x[10]
>> 0
x[10]=5
x[10]
>> 0
array.array('i',(0,)*10**8)
导致错误(lol)
您没有指定您得到了什么错误-这对我来说是有效的,尽管它不是很快,因为它构建了一个中间元组并立即丢弃它。使用Python的内置类型,array.array
可能会获得最佳性能,前提是避免使用元组:
a = array.array('i', (0,)) * 10**8
上面的代码只用了0.7秒。。。但是有没有办法让它更快呢
如果不允许创建或导入C扩展名,那么很难击败array.array。在我几年前的机器上,上述操作需要0.6秒。您可以通过增加初始数组的大小来进一步优化它。例如,这会产生相同的结果,但速度几乎快了3倍(!):
在我的机器上,以下版本效果最佳:
# 0.19 s
a = array.array('i', (0,) * 100) * 10**6
进一步增加初始阵列大小没有帮助,很快就会开始降低性能
<> P>为了获得更好的效率,考虑替代的方法,如懒惰的列表或为您的用例定制的完全不同的数据结构。考虑到竞争的背景,这可能是人们真正寻求的
但是,请注意,每个解决方案都有不同的权衡。例如,@KonstantinNikitin提供的惰性数组将非常高效地构造,但是它的\uuuu getitem\uuuuuuu
和\uuuu setitem\uuuuuu
在纯Python中实现,将比list或array.array
慢几个数量级。哪一个对您更有利归结为您的程序中哪些操作更频繁,这取决于您自己去发现。如果您真的只想要这两个属性:
获取某个索引中的对象(1)并更改其值(2)
然后您可以只使用集合。defaultdict:
import collections
my_list = collections.defaultdict(lambda: 0)
这相当快(~0.4μs):
但是,实际使用它可能比其他答案中建议的任何类型都要慢。对于只需要0到255之间的整数的情况,
bytearray
对象创建速度非常快:
>>> 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
与
array.array
不同,它直接将分配归零,而不是从用零初始化的对象复制。您是否考虑过numpy
?如果您谈论的是大型数值计算中的性能,那么不必担心导入模块。看你也有bytearray(10**8)
。值的范围是有限的(0-255),但它非常快使用字典可能很慢。。。插入和获取索引操作可能需要O(1),但也可能需要O(n)(最坏情况)是的,延迟初始化有它自己的代价。你可以试着混合。就像手动将间隔拆分为[0..sqrt(size)]dicts列表一样,我没有指定eror,因为当我在我的机器上运行它时
import collections
my_list = collections.defaultdict(lambda: 0)
$ python3 -m timeit -s 'import collections' 'collections.defaultdict(lambda: 0)'
1000000 loops, best of 3: 0.417 usec per loop
>>> 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