2009-09-17 57 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 

我认为这是最好的做所有的位掩饰和转移自己!