4

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

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

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

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

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

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
4

6 回答 6

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

于 2009-06-29T13:56:34.270 回答
5

您可以将一些具有不同的两个值的幂的常量定义为:

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

并将它们与布尔逻辑一起使用,以仅将标志存储在一个整数 pe 中:

flags = FLAG1 | FLAG8

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

flag1_enabled = flags & FLAG1

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

于 2009-06-29T14:04:42.117 回答
5

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

如果由于某种原因我无法承受 numpy 依赖项(例如,在不支持 numpy 的 App Engine 上),我会使用标准库数组模块——它只支持一维数组,但它就像空格一样——对于大型同构数组而言,它与 numpy 一样有效,并且您提到的 getter/setter 例程可以完美地“线性化”一个 3 项元组,该元组是您对 1-D 数组的单个整数索引的自然索引。

一般来说,只要你有大的同质、密集的向量或数字矩阵,就考虑使用 numpy(或数组)——在这个用例中,Python 内置列表非常浪费空间(由于它们的通用性,你没有使用和这里不需要!-),节省内存也间接转化为节省时间(更好的缓存,更少的间接级别等)。

于 2009-06-29T14:09:34.743 回答
3

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

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

于 2009-06-29T14:00:25.887 回答
1

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

于 2009-06-29T13:53:34.713 回答
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__使其更易于使用。

于 2009-06-29T14:13:39.993 回答