2012-06-19 20 views
11

Estoy buscando una estructura de datos que contenga los mismos valores en dos índices diferentes, donde puedo acceder a los datos por uno.Estructura de datos para implementar un diccionario con índices múltiples?

Ejemplo:

x = mysticalDataStructure() 
x.add(1,'karl', dog) 
x.add(2,'lisa', cat) 

$ x[1].age 
2 
$ x['karl'].age 
2 
$ x[1].age = 4 
$ x['karl'].age 
4 

¿Hay algo prerolled, o lo que es el mejor enfoque para rodar mi propia (Necesito acceso a través de un índice (número que va de 0 a N en incrementos de 1), ya través de una cuerda).

collections.ordereddict Parece que no tiene acceso aleatorio rápido a través de la posición, por lo que veo, solo puedo caminarlo con el iterador hasta que llego al elemento i (puedo insertarlo en el orden correcto).

+0

Si cambia un valor a través de una tecla, qué se puede esperar del nuevo valor que se recuperará con la otra clave? – martineau

+0

@martineau: sí exactamente – ted

+0

Ver esta respuesta/módulo: http://stackoverflow.com/questions/11449232/multiple-keys-per-value/16966988#16966988 – formiaczek

Respuesta

7
class MultiKeyDict(object): 

    def __init__(self, **kwargs): 
     self._keys = {} 
     self._data = {} 
     for k, v in kwargs.iteritems(): 
      self[k] = v 

    def __getitem__(self, key): 
     try: 
      return self._data[key] 
     except KeyError: 
      return self._data[self._keys[key]] 

    def __setitem__(self, key, val): 
     try: 
      self._data[self._keys[key]] = val 
     except KeyError: 
      if isinstance(key, tuple): 
       if not key: 
        raise ValueError(u'Empty tuple cannot be used as a key') 
       key, other_keys = key[0], key[1:] 
      else: 
       other_keys = [] 
      self._data[key] = val 
      for k in other_keys: 
       self._keys[k] = key 

    def add_keys(self, to_key, new_keys): 
     if to_key not in self._data: 
      to_key = self._keys[to_key] 
     for key in new_keys: 
      self._keys[key] = to_key 


    @classmethod 
    def from_dict(cls, dic): 
     result = cls() 
     for key, val in dic.items(): 
      result[key] = val 
     return result 

Uso:

>>> d = MultiKeyDict(a=1, b=2) 
>>> d['c', 'd'] = 3 # two keys for one value 
>>> print d['c'], d['d'] 
3 3 
>>> d['c'] = 4 
>>> print d['d'] 
4 
>>> d.add_keys('d', ('e',)) 
>>> d['e'] 
4 
>>> d2 = MultiKeyDict.from_dict({ ('a', 'b'): 1 }) 
>>> d2['a'] = 2 
>>> d2['b'] 
2 
+1

Probablemente debería tener un '__delitem __()' también. – martineau

+0

@martineau, esto es solo un boceto para explicar el concepto – astynax

+0

perfecto, esto es realmente increíble, mientras que necesito hacer dos accesos a la lista, también puedo almacenar instancias de tipos inmutables. – ted

1

Solo tiene que utilizar tres mapas.

maps = [dict(), dict(), dict()] 

def insert(rec): 
    maps[0][rec[0]] = rec 
    maps[1][rec[1]] = rec 
    maps[2][rec[2]] = rec 

Sin embargo, los cambios en los atributos clave del objeto rec requerirán reinserción. Al igual que cualquier otro mapa, cuando cambias la clave de un objeto.

Los mapas simplemente asignan la clave -> objeto, después de todo. En realidad, no almacenan copias del objeto (simplemente no es basura). Entonces, un mapa es un índice, nada más. Si quiere tres índices, use tres mapas. Escribe un par de funciones de código de pegamento para administrarlas.

Como se ha mencionado por Trevor, también se puede usar un diccionario común:

index = dict() 

def insert(rec): 
    index[rec[0]] = rec 
    index[rec[1]] = rec 
    index[rec[2]] = rec 

entonces usted puede acceder a ella por cualquiera.

¡Sin embargo, tenga cuidado con las colisiones clave!

+0

1 contesta mi ejemplo mal formulado, pero olvidaste, por ejemplo, que también tengo índices que no provienen del objeto, por ejemplo '1' como una identificación para el' perro' – ted

11

¿Hay alguna razón particular, no se puede simplemente usar un diccionario:

x = {} 
x[1] = x['karl'] = dog 
x[2] = x['lisa'] = cat 

A continuación, se puede acceder a ella por cualquiera.

Si realmente no quiere repetir su auto usted hace esto:

class MysticalDataStructure(dict): 
    def add(self, key1, key2, value): 
     return self[key1] = self[key2] = value 

x = MysticalDataStructure() 
x.add(1, 'karl', dog) 
x.add(2, 'lisa', cat) 
+0

Esto también es bueno, usando un índice compartido. –

+0

no modificaría x [1] no modificaría x ['karl']? –

+0

@Hans, por supuesto, se modificaría, es el mismo objeto: los objetos se pasan como referencias en python (por el valor de la referencia del objeto, consulte http: // stackoverflow.com/a/986145/1176601) – Aprillion

Cuestiones relacionadas