Python中的标志

时间:2009-06-29 13:49:38

标签: python matrix numpy flags

我正在使用一个大矩阵(250x250x30 = 1,875,000个单元格),我想要一种方法为这个矩阵中的每个单元设置任意数量的标志,以某种方式易于使用且合理节省空间

我原来的计划是250x250x30列表数组,其中每个元素都是:["FLAG1","FLAG8","FLAG12"]。然后我将其更改为仅存储整数:[1,8,12]。这些整数由getter / setter函数在内部映射到原始标志字符串。这只使用250mb,每点8个标志,这在内存方面很好。

我的问题是:我是否错过了构建此类数据的另一种明显方法?

感谢大家的建议。我最后将一些建议合而为一,遗憾的是我只能选择一个答案并且不得不接受其他人的支持:

编辑:我在这里使用的初始代码(使用sets作为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 个答案:

答案 0 :(得分:7)

如果每个单元格都有标记,那么您的解决方案就可以了。但是,如果您正在使用稀疏数据集,其中只有一小部分单元格会有标记您真正想要的是字典。您可能需要设置dictonary,因此键是单元格位置的元组,值是您在解决方案中的标记列表。

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和字典语法。

答案 1 :(得分:5)

您可以使用两个值的不同功率定义一些常量:

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

并使用布尔逻辑将它们存储在一个整数中,例如:

flags = FLAG1 | FLAG8

要检查是否启用了标记,您可以使用&运算符:

flag1_enabled = flags & FLAG1

如果启用了该标志,则该表达式将返回一个非零值,该值将在任何布尔运算中计算为True。如果禁用该标志,则表达式将返回0,在布尔运算中将其计算为False。

答案 2 :(得分:4)

我通常会使用一个numpy数组(大概是短整数,每个2个字节,因为你可能需要超过256个不同的值) - 对于< 2百万个单元格而言,这将花费不到4MB。

如果由于某种原因我无法负担numpy依赖(例如在不支持numpy的App Engine上),我会使用标准库array模块 - 它只支持1维数组,但它对于大型同构数组来说就像numpy一样节省空间,并且你提到的getter / setter例程可以很好地“线性化”一个3项元组,这是你自然索引到单个整数索引中的1-D数组。

一般情况下,只要有大型同构,密集向量或数字矩阵,就考虑numpy(或数组) - 在这个用例中,Python内置列表非常浪费空间(由于它们的普遍性,你是不使用也不需要这里! - ),间接节省内存也可以节省时间(更好的缓存,更少的间接等等)。

答案 3 :(得分:3)

考虑使用Flyweight模式来共享单元格属性:

http://en.wikipedia.org/wiki/Flyweight_pattern

答案 4 :(得分:1)

BitSet是你想要的,因为它允许你只使用固定大小的整数(Int类型)一次存储许多标志

答案 5 :(得分:1)

将罗比的建议更进一步......

flags = set()
x, y, flag = 34, 201, 3
flags.add((x, y, flag)) # set flag 3 at position (34, 201)
if (3, 2, 1) in flags: # check if flag 1 is at position (3, 2)
    # do something
else:
    # do something else

您还可以创建一个帮助类。

class Flags(object):
    def __init__(self):
        self.data = set()
    def add(self, x, y, flag):
        self.data.add((x, y, flag))
    def remove(self, x, y, flag):
        self.data.remove((x, y, flag))
    def contains(self, x, y, flag):
        return (x, y, flag) in self.data

您还可以实现Python的特殊方法,如__contains__,以便更轻松地使用。