Pregunta

Estoy trabajando con una matriz grande (250x250x30 = 1.875.000 células), y me gustaría una manera de establecer un número arbitrario de banderas para cada celda en esta matriz, de alguna manera que es fácil de usar y razonablemente eficiente del espacio .

Mi plan original era una matriz 250x250x30 lista, donde cada elemento era algo así como: ["FLAG1","FLAG8","FLAG12"]. a continuación, lo cambié a almacenar simplemente números enteros en su lugar: [1,8,12]. Estos números enteros se asignan internamente por funciones de captador / definidor a las cuerdas bandera original. Esto sólo se utiliza 250mb con 8 banderas por punto, lo cual está bien en términos de memoria.

Mi pregunta es: ¿Me estoy perdiendo otra manera obvia para estructurar este tipo de datos

Gracias a todos por sus sugerencias. Acabé rodando algunas sugerencias en uno solo, por desgracia sólo puedo elegir una respuesta y tener que vivir con los demás Upvoting:

EDIT: erm el código inicial que tuve aquí (utilizando conjuntos como el elemento de base de una matriz de numpy 3d) utilizado una gran cantidad de memoria. Esta nueva versión utiliza alrededor de 500 mb, cuando se llena de 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
¿Fue útil?

Solución

Me generalmente utilizar un numpy array (presumiblemente de enteros cortos, 2 bytes cada uno, ya que es posible necesita más de 256 valores distintos) -. eso sería tomar menos de 4 MB para los <2 millones de células

Si por alguna razón no podía permitirse la dependencia numpy (por ejemplo en App Engine, que no soporta numpy), que haría uso de la biblioteca estándar módulo de gama - sólo es compatible con las matrices de 1 dimensión, pero es igual de eficiente con el espacio como numpy para grandes matrices homogéneas, y las captador / definidor le rutinas mención puede perfectamente bien "linealizar" un 3-artículos tupla que es su índice natural en el índice entero simple en la matriz 1-D.

En general, considere numpy (o matriz) cada vez que tenga grandes, vectores o matrices de números homogéneos densos - Python listas integradas son altamente derrochador del espacio en este caso de uso (debido a su generalidad, que eres no usar y no necesitan aquí -.), y el ahorro de memoria se traduce indirectamente con el ahorro de tiempo también (mejor almacenamiento en caché, menos niveles de indirección, etc, etc)

Otros consejos

Su solución es bien si cada célula va a tener una bandera. Sin embargo, si se está trabajando con un conjunto de datos escasa que sólo una pequeña subsección de sus células tendrá banderas lo que realmente quiere es un diccionario. Usted desea configurar el Dictonary lo que la clave es una tupla para la ubicación de la celda y el valor es una lista de banderas como que tiene en su solución.

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

Aquí tenemos la célula 1,1,1 tienen las banderas 1,2, y 3 y la célula 250,250,30 tienen las banderas 4,5, y 6

Editar- fija tuplas clave, gracias a Andre y sintaxis diccionario.

Se pueden definir algunas constantes con el diferente, el poder de dos valores como:

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

y utilizarlos con la lógica booleana para almacenar las banderas en un solo número entero, P.E:.

flags = FLAG1 | FLAG8

Para comprobar si se ha activado una bandera, se puede utilizar el operador de &:

flag1_enabled = flags & FLAG1

Si se activa la bandera, esta expresión devolverá un valor distinto de cero, que será evaluada como verdadera en cualquier operación booleana. Si la bandera está desactivada, la expresión devolverá 0, que se evalúa como False en operaciones booleanas.

Considere el uso de flyweight a compartir propiedades de células:

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

BitSet es lo que desea, ya que le permite almacenar muchas banderas a la vez utilizando solamente un tamaño entero fijo (tipo Int)

Tomando un paso más allá sugerencia de Robbie ...

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

También puede crear una clase de ayuda.

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

También se puede poner en práctica métodos especiales de Python como __contains__ para que sea más fácil trabajar con ellos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top