2011-01-21 7 views
6

Tengo una serie de objetos que debo vincular a un número entero. Estos objetos son objetos de punto de ArcGIS (exactamente lo que son no son relevantes), que almacenan un X y un valor de Y para un punto, como números de coma flotante.Índice dict de python por objeto o dos flotantes

necesito dejar constancia de que, por ejemplo:

Point(X = 2.765, Y = 3.982) -> 2 
Point(X = 33.9, Y = 98.45) -> 7 
Point(X = 1.23, Y = 2.43) -> 9 
Point(X = 8.342, Y = 6.754) -> 5 

entonces tienen que ser capaces de buscar el valor resultante por los valores X e Y. Intenté usar los objetos Point como la clave del diccionario, pero esto no funciona, porque cuando recreo el objeto de punto a partir de los valores X e Y ya no lo veo correctamente (presumiblemente porque el ID del objeto ha cambiado) .

¿Cómo debo vincular estos valores de punto a los enteros? ¿Hay alguna otra manera en que pueda usar un diccionario?

Respuesta

4

Las claves del diccionario de Python deben ser tipos inmutables.

Puede usar una tupla como (2.765, 3.982). Siempre que una tupla contenga solo tipos inmutables, puede usarse como una clave de diccionario.

Aquí está mi prueba en la consola:

>>> my_dict[(12.3151, 1.2541)] = "test" 
>>> my_dict[(12.3151, 1.2541)] 
'test' 

Usted podría llegar a un simple convención de cadena como "2.765, 3.982" a su vez un punto en un índice, pero eso sería un desperdicio de procesamiento. Además, una palabra de advertencia: si por alguna razón elige hacer esto, debe usar repr en lugar de str (here's una publicación de Desbordamiento de pila sobre ese tema).

+0

Gracias. Sin embargo, esto causará problemas con los flotadores, ya que no se pueden almacenar exactamente. Solo me preocupa que convertir flotadores en cadenas y utilizarlos para indexar genere problemas con flotantes que no se convierten muy bien en cadenas (y flotantes que ni siquiera se pueden almacenar exactamente en la memoria). – robintw

+0

@robintw si necesita precisión de coma flotante, consulte el módulo decimal http://docs.python.org/library/decimal.html – admalledd

+0

@robintw - No lo he probado, pero creo que @admalledd es correcto. ¿Puedes seleccionar una respuesta o compartir cómo resolviste el problema? –

1
+1

Este es un problema un poco más complicado, porque __hash__ tiene que devolver un número entero. Necesitaría ID únicos únicos para cada Punto (es decir, el código y la sobrecarga de la máquina para mantener un registro) o una transformación entera que pueda aplicarse a '(flotar, flotar)' y generar enteros únicos, y estoy en una pérdida por tener uno de esos en la cima de mi cabeza. –

+2

@dorkitude: puedes hacer hash (some_float) para convertir un float en un entero único: usa Python's built-in. –

+0

@josh ¡eso es genial! pero el problema persiste: estamos tratando de transformar dos flotadores en un entero único. –

10

añadir un método de hash para su clase Point:

... 
def __hash__(self): 
    return hash(self.x)^hash(self.y) 
... 

En otras palabras, el hash de un punto es un munging del hash de las coordenadas x e y.

EDIT: una mejor función hash (basado en los comentarios aquí) es:

... 
def __hash__(self): 
    return hash((self.x, self.y)) 
... 

Debido Python hashes tuplas de una manera que hash((p,q)) no es igual a hash((q,p)), esto va a evitar las colisiones de condensación de puntos simétrica con respecto a la diagonal .

A continuación, puede utilizar el objeto Point como claves para los diccionarios, los puso en conjuntos, etc.

+0

Eso suena bien, pero el problema es que no escribí la clase Point: proviene de la API de ArcGIS. ¿Hay alguna manera de 'insertar'/'anular' los métodos para insertar ese tipo de código hash en el método? – robintw

+1

@robintw Hay: Point .__ hash__ = lambda self: return hash (self.x)^hash (self.y) –

+0

@robintw: Además, puede crear su propia clase subclasificada desde Point: 'class HashPoint (Point): [definición de clase ...] 'que podría ser más fácil de mantener. – senderle

1

Añadir un método __hash__() a la clase punto como Payne dijo. O calcula manualmente un hash para cada punto. En cualquier caso, use algo como lo que haría originalmente Python:

... 
def __hash__(self): 
    return hash((self.x, self.y)) 
... 
Cuestiones relacionadas