Python中的标志

4 投票
6 回答
10050 浏览
提问于 2025-04-15 12:34

我正在处理一个很大的矩阵(250x250x30 = 1,875,000个单元格),我想为这个矩阵中的每个单元格设置一些标志,要求使用起来简单,并且占用空间合理。

我最开始的计划是用一个250x250x30的列表数组,每个元素像这样:["FLAG1","FLAG8","FLAG12"]。后来我改成只存储整数:[1,8,12]。这些整数通过一些函数内部映射到原来的标志字符串。这样做只用了250MB的内存,每个点有8个标志,这在内存使用上是可以接受的。

我想问的是:我是不是错过了其他明显的方式来组织这种数据?

谢谢大家的建议。我最后把几个建议合并成一个,遗憾的是我只能选择一个答案,并且只能给其他的点赞:

补充:嗯,我最开始的代码(使用集合作为3D numpy数组的基本元素)占用了很多内存。这个新版本在填充了randint(0,2**1000)后大约使用了500MB。

import numpy

FLAG1=2**0
FLAG2=2**1
FLAG3=2**2
FLAG4=2**3

(x,y,z) = (250,250,30)

array = numpy.zeros((x,y,z), dtype=object)


def setFlag(location,flag):
    array[location] |= flag
def unsetFlag(location,flag):
    array[location] &= ~flag

6 个回答

5

你可以定义一些常量,这些常量的值是不同的2的幂次方,比如:

FLAG1 = 0x01
FLAG8 = 0x02
FLAG12 = 0x04
...

然后你可以用布尔逻辑把这些常量存储在一个整数里,这样可以节省空间,例如:

flags = FLAG1 | FLAG8

要检查一个标志是否被启用,你可以使用 & 运算符:

flag1_enabled = flags & FLAG1

如果这个标志被启用,这个表达式会返回一个非零的值,在任何布尔运算中都会被视为真。如果这个标志被禁用,表达式会返回0,在布尔运算中会被视为假。

7

你的解决方案很好,如果每个单元格都有一个标记的话。不过,如果你处理的是一个稀疏的数据集,也就是说只有一小部分单元格有标记,那么你其实需要用字典来处理。你可以把字典设置成,键是一个元组,表示单元格的位置,而值是一个标记的列表,就像你在解决方案中那样。

allFlags = {(1,1,1):[1,2,3], (250,250,30):[4,5,6]}

在这里,位置为1,1,1的单元格有标记1、2和3,而位置为250,250,30的单元格有标记4、5和6。

编辑:修正了键的元组,感谢Andre,以及字典的语法。

5

我一般会使用一个numpy数组(假设是短整型,每个占2个字节,因为你可能需要超过256个不同的值)——这样对于不到200万的单元格来说,所需的内存不会超过4MB。

如果因为某种原因我不能使用numpy(比如在不支持numpy的App Engine上),我会用标准库中的array模块——它只支持一维数组,但在处理大规模相同类型的数组时,和numpy一样节省空间。而你提到的获取和设置的功能,可以很好地把一个包含3个元素的元组“线性化”,这样就能用一个整数索引来访问一维数组。

总的来说,当你有大量相同类型、密集的数字向量或矩阵时,考虑使用numpy(或array)——Python内置的列表在这种情况下会浪费很多空间(因为它们的通用性在这里并不需要!),而节省内存间接意味着节省时间(比如更好的缓存,减少间接访问的层级等等)。

撰写回答