2012-03-28 17 views
21

Ich habe od vom Typ OrderedDict. Ich möchte auf das zuletzt hinzugefügte Paar (Schlüssel, Wert) zugreifen. od.popitem(last = True) würde es tun, aber würde auch das Paar aus od entfernen, die ich nicht will.Letztes Element in OrderedDict

Was ist eine gute Möglichkeit, das zu tun? Kann/soll ich dies tun:

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

Antwort

38

next(reversed(od)) zu verwenden ist eine perfekte Weise, die am meisten kürzlich hinzugefügte Element zuzugreifen. Die Klasse OrderedDict verwendet eine doppelt verkettete Liste für die Wörterbuchelemente und implementiert __reversed__(), so dass diese Implementierung Ihnen O (1) Zugriff auf das gewünschte Element gibt. Ob es sich lohnt, für diese einfache Operation die Unterklasse OrderedDict() zu unterteilen, kann in Frage gestellt werden, aber es ist eigentlich nichts falsch mit diesem Ansatz.

+0

Aber das gibt nur den Schlüssel des letzten Artikels in der OD, richtig? nicht der gesamte Gegenstand (Schlüssel, Wert). 'next (reversed (OrderedDict ([(0, 'a'), (1, 'b'), (2, 'c')]))) ergibt '2' nicht '(2,' c ')' – hobs

+14

@hobs: Ja, es gibt Ihnen nur den Schlüssel. Wie man den gegebenen Wert erhält, bleibt dem Leser als Übung überlassen. :) –

+0

:) also ist es O (2) für das OP-Problem. Details Ich weiß ... – hobs

1

Ihre Idee ist gut, aber der Standard-Iterator ist nur über die Schlüssel, so wird Ihr Beispiel nur den letzten Schlüssel zurückgeben. Was Sie wirklich wollen, ist:

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

Dies ergibt die (key, value) Paare, nicht nur die Schlüssel, wie man wollte.

Beachten Sie, dass auf Pre-3.x-Versionen von Python, OrderedDict.items() eine Liste, so dass Sie den list() Anruf nicht benötigen, aber spätere Versionen geben einen dictionary view object, so werden Sie.

Edit: Wie in den Kommentaren erwähnt, desto schneller Betrieb zu tun ist:

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

Obwohl ich mich finde diese hässliche im Code muss zugeben (ich nie gemocht dann den Schlüssel bekam x[key] tun zu bekommen der Wert getrennt, ich bevorzuge die (key, value) Tupel) - abhängig von der Wichtigkeit der Geschwindigkeit und Ihrer Vorlieben, möchten Sie vielleicht die vorherige Option wählen.

+2

Dies ist natürlich eine O (n) -Operation. Es wäre besser, die ursprüngliche Implementierung zu verwenden, um den Schlüssel zu erhalten, und den Wert durch normalen Wörterbuchzugriff zu erhalten. (Und wenn Sie sowieso eine Liste erstellen müssen, ist '[-1]' viel einfacher als 'next (reversed (...))'.) –

+0

Sie machen einen guten Punkt, korrigiert. Zu einfach, um sich auf eine Art zu lösen, ein Problem zu lösen. –

9

Ein wenig Magie von timeit hier helfen ...

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

Ergebnisse in:

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

(Getestet auf python3.2, Ubuntu Linux).

Wie von @SvenMarnach gezeigt, ist die von Ihnen beschriebene Methode ziemlich effizient im Vergleich zu den anderen zwei Möglichkeiten, die ich kochen konnte.

Verwandte Themen