2009-09-17 55 views
2

我試圖通過引用它們作爲索引在布爾數組中縮短10B順序整數的內存佔用量。換句話說,我需要創建一個包含10,000,000,000個元素的數組,但這很好地融入了「長」範圍。當我嘗試引用大於sys.maxint的數組索引時,數組爆炸了:python中的長索引數組

 
x = [False] * 10000000000 
Traceback (most recent call last): 
    File "", line 1, in 
    x = [0] * 10000000000 
OverflowError: cannot fit 'long' into an index-sized integer 

我能做什麼?我似乎無法找到網絡上的任何人有這個問題......大概答案是「蟒蛇無法處理大於2B的陣列」。

+0

哇,認真嗎?即使你可以這樣做,這樣的陣列也不太適合即使是64 GB的機器。我會建議一種不同的方法。 – 2009-09-17 02:30:18

+0

布爾值是一位。 10bil比特= 1.25兆字節。 – inanutshellus 2009-09-17 02:36:42

+0

(請糾正我的假設,如果我錯了!) – inanutshellus 2009-09-17 02:39:06

回答

5

對於32位地址空間,任何語言都會努力尋找這樣一個數組。那麼你的計算機上有多少真實的內存呢?

如果你想10B數組元素,代表真或假的每個元素,使用array.array(「我」,...)...

container = array.array('I', [0]) * ((10000000000 + 31) // 32) 

然後你可以設置和清除位使用通常的掩蔽和移位操作。

備選:

如果只有元素少數是真實的,或只是元素少數是假的,你可以使用的最佳內存節省一組,或用於編程方便的字典。

+1

+1:True元素的集合通常比「巨型位元組」的解決方案更高效。 – 2009-09-17 12:07:34

0

從一些Google搜索PEP 353(假設我瞭解它)和this exchange它看起來像真正的問題可能是平臺/系統依賴。你有足夠的內存來處理10,000,000,000條記錄嗎?

+0

我沒有空間容量爲10B的整數(這可能是40G內存),但我肯定有空間容納10B布爾(1.25MB的內存,假設Python是理智的) – inanutshellus 2009-09-17 02:38:03

+0

你打算如何將10億布爾變成10百萬位? – recursive 2009-09-17 02:42:02

+0

我的意思是1.25GB,感謝您注意:) – inanutshellus 2009-09-17 02:51:26

2

10B布爾(內存1.25MB,假設Python是理智)

我覺得你有你的算術錯誤 - supercompactly存儲,10B布爾是1.25 GIGA,_not__ MEGA ,字節。

一個列表每個項目至少需要4個字節,所以您需要40GB以您想要的方式完成。

您可以存儲陣列(請參閱標準庫中的array模塊)的內存要少得多,因此它可能適合。

3

密集位矢量是合理的,但它不會是最優的,除非你知道你不會有超過約10**10元素,所有元素都聚集在一起,並且具有合理的隨機分佈。如果你有不同的分佈,那麼不同的結構會更好。例如,如果您知道在該範圍內[0,10 ** 10],只有少數成員存在,請使用set(),或者如果情況相反,幾乎每個存在的元素除外分數,使用否定集合,即element not in mySet

如果元素傾向於圍繞小範圍聚類,可以使用運行長度編碼,比如[xrange(0,10),xrange(10,15),xrange(15,100)],通過平分直到找到匹配範圍,如果索引是偶數,則該元素是在集合中。插入和移除涉及對範圍進行一些改動。

如果您的發行版確實很密集,但您需要的內容比內存中的內容多一點(在實踐中似乎很典型),那麼您可以使用mmap管理內存,並使用類似的適配器包裝映射文件建議的array('I')解決方案的機制。

要了解您可能獲得的壓縮程度,請嘗試使用打包形式的合理語料庫構建純文件,然後應用常規壓縮算法(如gzip)以查看您看到多少壓縮。如果減少很多,那麼你也可以在代碼中使用某種空間優化。

4

​​包看起來可能是另一個有用的選項。

1

非常大的位陣列的另一種選擇是使用bitstring。它使用bytearray(或舊的Python版本中的array.array)來存儲數據,但其接口只是一個位數組。爲你的情況,你可以使用:

>>> from bitstring import BitString 
>>> s = BitString(10000000000)   # zero initialised 
>>> s.set([9, 999999999, 253])   # set 3 bits to '1' 
>>> s[66] = True      # set another bit 
>>> s.allset([9, 66])     # check if bits are set to '1' 
True 

我認爲這是最好的做所有的位掩飾和轉移自己!