2012-03-28 15 views
21

Ho od di tipo OrderedDict. Voglio accedere alla sua coppia aggiunta (chiave, valore) più recente. od.popitem(last = True) lo farebbe, ma rimuoverebbe anche la coppia da od che non desidero.Ultimo elemento in OrderedDict

Qual è un buon modo per farlo? Posso/devo fare questo:

class MyOrderedDict(OrderedDict): 
    def last(self): 
    return next(reversed(self)) 

risposta

38

Utilizzando next(reversed(od)) è un modo perfetto di accesso l'elemento più-recentemente aggiunto. La classe OrderedDict utilizza un elenco doppiamente collegato per gli elementi del dizionario e gli strumenti __reversed__(), quindi questa implementazione fornisce l'accesso O (1) all'elemento desiderato. Se valga la pena sottoclasse OrderedDict() per questa semplice operazione potrebbe essere messo in discussione, ma non c'è nulla di sbagliato in questo approccio.

+0

Ma questo restituisce solo la chiave dell'ultimo elemento nell'OD, giusto? non l'intero oggetto (chiave, valore). 'next (reverse (OrderedDict ([(0, 'a'), (1, 'b'), (2, 'c')])))' non '' '' '(2, 'c')' – hobs

+14

@hobs: Sì, fornisce solo la chiave. Come ottenere il valore dato la chiave è lasciata come esercizio al lettore. :) –

+0

:) quindi è O (2) per il problema dell'OP. dettagli che conosco ... – hobs

1

L'idea è a posto, tuttavia l'iteratore predefinito si trova solo sopra i tasti, quindi l'esempio restituirà solo l'ultima chiave. Che cosa si vuole realmente è:

class MyOrderedDict(OrderedDict): 
    def last(self): 
     return list(self.items())[-1] 

Questo dà la (key, value) coppie, non solo le chiavi, come si voleva.

Si noti che sulle versioni pre-3.x di Python, OrderedDict.items() restituisce una lista, quindi non è necessario la chiamata list(), ma le versioni successive restituire un dictionary view object, così si farà.

Edit: Come notato nei commenti, l'operazione più veloce è quello di fare:

class MyOrderedDict(OrderedDict): 
    def last(self): 
     key = next(reversed(self)) 
     return (key, self[key]) 

Anche se devo ammettere che trovo questa brutta nel codice (mi è mai piaciuto ottenere la chiave poi facendo x[key] per ottenere il valore separatamente, preferisco ottenere la tupla (key, value)) - a seconda dell'importanza della velocità e delle preferenze, potresti voler scegliere l'opzione precedente.

+2

Questa sarà un'operazione O (n), ovviamente. È preferibile utilizzare l'implementazione originale per ottenere la chiave e ottenere il valore tramite il normale accesso al dizionario. (E quando comunque devi compilare una lista, '[-1]' è molto più facile di 'next (invertito (...))'.) –

+0

Hai fatto un buon punto, corretto. Troppo facile per essere bloccato in un modo di risolvere un problema. –

9

Un po 'di magia da timeit può aiutare qui ...

from collections import OrderedDict 
class MyOrderedDict1(OrderedDict): 
    def last(self): 
    k=next(reversed(self)) 
    return (k,self[k]) 

class MyOrderedDict2(OrderedDict): 
    def last(self): 
    out=self.popitem() 
    self[out[0]]=out[1] 
    return out 

class MyOrderedDict3(OrderedDict): 
    def last(self): 
    k=(list(self.keys()))[-1] 
    return (k,self[k]) 

if __name__ == "__main__": 
    from timeit import Timer 

    N=100 

    d1=MyOrderedDict1() 
    for i in range(N): d1[i]=i 

    print ("d1",d1.last()) 

    d2=MyOrderedDict2() 
    for i in range(N): d2[i]=i 

    print ("d2",d2.last()) 

    d3=MyOrderedDict3() 
    for i in range(N): d3[i]=i 

    print("d3",d3.last()) 



    t=Timer("d1.last()",'from __main__ import d1') 
    print ("OrderedDict1",t.timeit()) 
    t=Timer("d2.last()",'from __main__ import d2') 
    print ("OrderedDict2",t.timeit()) 
    t=Timer("d3.last()",'from __main__ import d3') 
    print ("OrderedDict3",t.timeit()) 

risultati in:

d1 (99, 99) 
d2 (99, 99) 
d3 (99, 99) 
OrderedDict1 1.159217119216919 
OrderedDict2 3.3667118549346924 
OrderedDict3 24.030261993408203 

(Testato su python3.2, Ubuntu Linux).

Come sottolineato da @SvenMarnach, il metodo che hai descritto è abbastanza efficiente rispetto agli altri due modi in cui posso cucinare.

Problemi correlati