2012-06-19 15 views
11

Sto cercando una struttura dati che contenga gli stessi valori in due diversi indici, in cui posso accedere ai dati tramite o uno.Struttura dati per implementare un dizionario con più indici?

Esempio:

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 

C'è qualcosa prerolled, o che cosa è l'approccio migliore per rotolare il mio (ho bisogno di accesso tramite un indice (numero che va da 0 a n con incrementi di 1), e via una stringa).

collections.ordereddict non sembrano avere accesso casuale veloce tramite la posizione, per quanto vedo che posso camminare solo con l'iteratore fino a raggiungere elemento i (posso inserire nel giusto ordine).

+0

Se si modifica un valore attraverso una chiave, vi aspettate il nuovo valore da recuperare con l'altra chiave? – martineau

+0

@martineau: sì esattamente – ted

+0

Vedere questa risposta/modulo: http://stackoverflow.com/questions/11449232/multiple-keys-per-value/16966988#16966988 – formiaczek

risposta

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 

Usage:

>>> 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

Probabilmente dovrebbe anche avere un '__delitem __()'. – martineau

+0

@martineau, questo è solo uno schizzo per spiegare il concetto – astynax

+0

perfetto, questo è semplicemente fantastico, mentre ho bisogno di fare due accessi alla lista posso anche memorizzare istanze di tipi immutabili. – ted

1

Basta usare tre mappe.

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

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

Modifiche a attributi chiave dell'oggetto rec richiederà il reinserimento però. Proprio come qualsiasi altra mappa, quando cambi la chiave di un oggetto.

Le mappe si limitano a mappare la chiave -> oggetto, dopotutto. In realtà non memorizzano le copie dell'oggetto (non è solo una raccolta di dati inutili). Quindi una mappa è un indice, niente di più. Se vuoi tre indici, usa tre mappe. Scrivi un paio di funzioni del codice della colla per gestirle.

Come accennato da Trevor, è anche possibile utilizzare un dizionario condiviso:

index = dict() 

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

allora si può accedere da entrambi.

Attenzione però alle collisioni di chiavi!

+0

+1 risponde il mio esempio mal formulato, ma per esempio hai dimenticato che ho anche indici che non provengono dall'oggetto, ad es '1' come un id per il' cane' – ted

11

C'è un motivo particolare non si può semplicemente utilizzare un dizionario:

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

Quindi è possibile accedervi da entrambi.

Se davvero non si vuole ripetere la vostra auto si esegue questa operazione:

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

Questo è anche bello, usando un indice condiviso. –

+0

non modifica x [1] non modifica x ['karl']? –

+0

@ Ovviamente sarebbe stato modificato, è lo stesso oggetto - gli oggetti vengono passati come riferimenti in python (in base al valore dell'oggetto reference - vedi http: // stackoverflow.it/a/986145/1176601) – Aprillion

Problemi correlati