Python中的标志

Python中的标志,python,matrix,numpy,flags,Python,Matrix,Numpy,Flags,我使用的是一个大型矩阵(250x250x30=1875000个单元格),我想用一种方法为这个矩阵中的每个单元格设置任意数量的标志,这种方法简单易用,节省空间 我最初的计划是一个250x250x30列表数组,其中每个元素类似于:[“FLAG1”、“FLAG8”、“FLAG12”]。然后我将它改为只存储整数:[1,8,12]。这些整数由getter/setter函数在内部映射到原始标志字符串。这只使用250mb,每个点有8个标志,这在内存方面很好 我的问题是:我是否遗漏了另一种构建此类数据的明显方式

我使用的是一个大型矩阵(250x250x30=1875000个单元格),我想用一种方法为这个矩阵中的每个单元格设置任意数量的标志,这种方法简单易用,节省空间

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

我的问题是:我是否遗漏了另一种构建此类数据的明显方式

谢谢大家的建议。最后我把几个建议合并成了一个,遗憾的是,我只能选择一个答案,而不得不接受对其他答案的投票:

编辑:erm我这里的初始代码(使用集合作为3d numpy数组的基本元素)使用了大量内存。这个新版本在填充
randint(0,2**1000)
时使用大约500mb


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

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

allFlags = {(1,1,1):[1,2,3], (250,250,30):[4,5,6]}
这里我们有1,1,1单元格有标志1,2和3,单元格250250,30有标志4,5和6


编辑-修复键元组,谢谢Andre和字典语法。

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


您可以使用两个值的不同幂定义一些常数,如下所示:

FLAG1 = 0x01
FLAG8 = 0x02
FLAG12 = 0x04
...
并将其与布尔逻辑一起使用,以仅将标志存储在一个整数中,即:

flags = FLAG1 | FLAG8
要检查标志是否已启用,可以使用
&
运算符:

flag1_enabled = flags & FLAG1

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

我通常会使用一个数组(可能是短整数,每个2字节,因为您可能需要超过256个不同的值)

进一步考虑Robbie的建议,这将花费不到4MB的时间

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的特殊方法,如
\uuuuuu contains\uuuuu
,以使其更易于使用。

您需要支持多少个标志?我不确定,我没有信心说任何比“大于5且小于500”更准确的方法。他使用的是三维矩阵,所以您需要说一些类似dict的东西((1,1,1)=[1,2,3]…实际上,那不应该是{(1,1,1):[1,2,3],…)。dict(key=val)语法仅在键为python标识符时有效。即使我使用多达100个对象,这也会为我节省大约20%的所需内存,非常有趣!一个问题,我如何删除标志?如果您可能真的有多达500个标志,可能不是最好的方法,尽管python支持任意长的整数。要删除标志,必须添加Its否定(flags&=~FLAG1)@Alex Jurkiewicz:new_flags=old_flags&~flags_to_remove。感谢您的建议。尽管我将使用集合而不是位字段(我不需要在此处节省额外的空间)我以后肯定会需要这样的东西。感谢numpy的建议。关于数据类型的一个问题。由于ushort可以容纳高达2**16的值,所以如果我使用ushort,我不能只有16个标志吗?对不起……我仍然像前面的回答一样考虑位标志。我现在明白你的意思了,一个4d数组,其中一个[0][0]返回1d数组是否正确?嗯,我对你的问题的理解有所不同,每个单元格只有一个标志(或无标志)(最多500个不同的值),而不是单个单元格最多500个标志。对于你的实际问题,确实需要一个4-D数组(每个单元格512位,64字节),因此是128MB(还有其他答案提到的移位和掩码的位/位转换)——如果你真的需要像那样“密集”(如果典型的单元格有几个标志,那么列表又很有吸引力,特别是在numpy中,你只需要最低级别的列表)。感谢这个想法。我最终使用了一个3d numpy集合数组(假设一个集合比一个列表更适合这个问题)。呃,集合太糟糕了。我在问题中粘贴的示例代码使用了python long的魔力。感谢numpy数组技巧。
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