![](/img/trans.png)
[英]Python - Fastest and most efficent way to convert a list-like string to a list of lists
[英]Fastest way to make a list-like object containing integers in python
這意味着我想擁有一個支持列表的兩個(非常)基本操作的對象:獲取某個索引(1)中的對象並更改其值(2)。
他們沒有解決我的問題,因為他們的所有解決方案都太慢了:在我的PC array.array('i',(0,)*10 ** 8)
導致錯誤(lol); [0 for _ in range(10**8)]
花了大約15秒(哇!); [0] * 10 ** 8
耗時2.3秒; [None] * 10 ** 8
了1.8秒; (1.8秒可能更快...)
我嘗試使用ctypes
模塊
from ctypes import c_int
array = (c_int * 10 ** 8)()
上面的代碼只花了0.7秒......但有沒有辦法讓它更快? 除了快速,它有一些缺點:
真的有可能做我要問的事嗎? 有沒有比使用ctypes
模塊更快的方法? 如果是這樣,請確保使用“內置”/“預安裝”模塊。
我正在使用python進行競爭性編程,大多數口譯/評委都不允許使用外部庫。
我可以看到很多答案都使用了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)]
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.22 s
a = array.array('i', (0,) * 10) * 10**7
在我的機器上,以下版本效果最佳:
# 0.19 s
a = array.array('i', (0,) * 100) * 10**6
進一步增加初始陣列大小並沒有幫助,很快就會開始降低性能。
為了獲得更高的效率,請考慮其他方法,例如惰性列表或為您的用例量身定制的完全不同的數據結構。 鑒於競爭的背景,這可能是實際上正在尋求的。
但請注意,每種解決方案都會有不同的權衡。 例如,像@KonstantinNikitin提供的惰性數組將非常有效地構造,但是在純Python中實現的__getitem__
和__setitem__
將比list或array.array
慢幾個數量級。 對您來說哪個更好,歸結為您的計划中更頻繁的操作,這取決於您找出答案。
我會使用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:
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
如果你真的只想要這兩個屬性:
獲取某個索引(1)中的對象並更改其值(2)
然后你可以使用collections.defaultdict
:
import collections
my_list = collections.defaultdict(lambda: 0)
相當快(~0.4μs):
$ python3 -m timeit -s 'import collections' 'collections.defaultdict(lambda: 0)'
1000000 loops, best of 3: 0.417 usec per loop
但是,實際使用它可能比其他答案中建議的任何類型都要慢一些。
對於只需要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
不同,這會直接將分配歸零,而不是從使用零初始化的對象進行復制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.