2012-09-08 17 views
8

Sto usando un OrderedDict ad accesso casuale un elenco, ma ora vogliono la voce next nella lista da quello che ho:Come ottenere l'elemento "successivo" in OrderedDict?

foo = OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)]) 
apple = foo['apple'] 

Come faccio ad avere la banana utilizzando solo foo e apple?

+1

'OrderedDict' sembra essere troppo semplice per questo. Forse un orribile one-liner avrebbe funzionato? 'foo [(lambda keys: keys [(keys.index ('pear') + 1)% len (keys)]) (foo.keys())]' – Blender

risposta

7

Se siete OK con l'accesso a quelle parti della realizzazione OrderedDict che sono intenzionalmente privato:

>>> class MyOrderedDict(OrderedDict): 
...  def next_key(self, key): 
...    next = self._OrderedDict__map[key][1] 
...    if next is self._OrderedDict__root: 
...      raise ValueError("{!r} is the last key".format(key)) 
...    return next[2] 
...  def first_key(self): 
...    for key in self: return key 
...    raise ValueError("OrderedDict() is empty") 
... 
>>> od = MyOrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)]) 
>>> od.next_key("apple") 
'banana' 
>>> od.next_key("banana") 
'orange' 
>>> od.next_key("orange") 
'pear' 
>>> od.next_key("pear") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in next_key 
ValueError: 'pear' is the last key 
>>> od.first_key() 
'apple' 
+1

Più che OK, è l'intuizione che speravo. –

+0

In python 3.4 l'implementazione di 'OrderedDict' è leggermente cambiata (si veda [qui] (https://hg.python.org/cpython/file/01437956ea67/Lib/collections/__init__.py#l85)). Gli elementi nell'elenco collegato ora sono oggetti della classe dummy '_Link'. Invece di accedere a 'self._OrderedDict__map [chiave] [1]', si dovrebbe accedere a 'self._OrderedDict__map [chiave] .next'. –

+0

In Python3.5 le cose sembrano essere ancora più cambiate. L'implementazione di OrderedDict viene spostata su C da python. Controlla [https://bugs.python.org/issue16991]. Questa implementazione non consentirà l'utilizzo di _map i.e. _OrderedDict__map. Nel caso in cui devi eludere questo e utilizzare il modulo python, puoi provare a utilizzare 'py_coll = import_fresh_module ('collections', blocked = ['_ collections']) OrderedDict = py_coll.OrderedDict' – Mikki

5

mi vengono i brividi a pensare quanto lento questo sarà su un elenco di dimensioni, ma l'unica modo in cui mi è venuta in mente finora ...

>>> foo.items()[foo.keys().index('apple') + 1] 
('banana', 3) 

Edit:

Il l'esempio era leggermente inventato; la mia collezione attuale è composta da date. Se ho bisogno della voce dopo today; trovato una soluzione utilizzando dropwhile ...

>>> foo = OrderedDict([(datetime.date(2000,1,1), 4), (datetime.date(2000,5,23), 3), datetime.date(2000,10,1), 2), (datetime.date(2000,12,31), 1)]) 
>>> today = datetime.date(2000,1,30) 
>>> foo.items()[foo.keys().index((itertools.dropwhile(lambda d: d<today, foo)).next())] 
(datetime.date(2000, 5, 23), 3) 

Piuttosto un boccone.

1

Rielaborato dal codice, in questo modo immagino che sarebbe un po 'meglio:

import collections as co 
import datetime as dt 
import itertools as it 

foo = co.OrderedDict([ 
    (dt.date(2000,1,1), 4), 
    (dt.date(2000,5,23), 3), 
    (dt.date(2000,10,1), 2), 
    (dt.date(2000,12,31), 1) 
]) 
today = dt.date(2000,1,30) 

fooiter = it.dropwhile(lambda d: d <= today, foo) 
print next(fooiter) 
print list(fooiter) 

avendo Fondamentalmente iteratore al posto giusto è già abbastanza.

Sarebbe bello avviare l'iterazione da qualsiasi posizione, ma non è sicuro se, quanto possibile. Ha bisogno di un pensiero.

Problemi correlati