70 votes

Dernier élément d'un OrderedDict

J'ai od de type OrderedDict . Je souhaite accéder à la paire (clé, valeur) la plus récemment ajoutée. od.popitem(last = True) le ferait, mais supprimerait également la paire de od ce que je ne veux pas.

Quelle est la meilleure façon de procéder ? Puis-je / dois-je faire cela ?

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

107voto

Sven Marnach Points 133943

L'utilisation next(reversed(od)) est un moyen parfait d'accéder à l'élément le plus récemment ajouté. La classe OrderedDict utilise une liste doublement liée pour les éléments du dictionnaire et met en œuvre la fonction __reversed__() Cette mise en œuvre vous donne donc un accès O(1) à l'élément désiré. La question de savoir s'il vaut la peine de sous-classer OrderedDict() pour cette simple opération peut être remise en question, mais il n'y a rien de mal à cette approche.

30voto

Hubert Grzeskowiak Points 5836

J'aimerais que toutes ces fonctionnalités soient intégrées...

Voici de quoi vous faire gagner un temps précieux. Testé en Python 3.7. od est votre OrderedDict.

# Get first key
next(iter(od))

# Get last key
next(reversed(od))

# Get first value
od[next(iter(od))]

# Get last value
od[next(reversed(od))]

# Get first key-value tuple
next(iter(od.items()))

# Get last key-value tuple
next(reversed(od.items()))

1 votes

Bons exemples, une seule observation, la méthode des clés n'est pas nécessaire

0 votes

Toutes ces opérations sont-elles O(1) ?

0 votes

@KnightKnight comme il n'y a pas de tri ou de comparaisons impliquées, et étant donné que la plupart des méthodes de collection de Python devraient être paresseuses, je parierais que oui. Mais ne me croyez pas sur parole lors d'une interview.

18voto

mgilson Points 92954

Un peu de magie de timeit peut aider ici...

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

se traduit par des résultats :

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

(Testé sur python3.2, Ubuntu Linux).

Comme l'a souligné @SvenMarnach, la méthode que vous avez décrite est assez efficace par rapport aux deux autres méthodes que j'ai pu mettre au point.

2voto

Lattyware Points 37257

Votre idée est bonne, mais l'itérateur par défaut ne porte que sur les clés, de sorte que votre exemple ne renverra que la dernière clé. Ce que vous voulez en fait, c'est :

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

Cela donne le (key, value) et non seulement les clés, comme vous le souhaitiez.

Notez que sur les versions de Python antérieures à la version 3.x, OrderedDict.items() renvoie une liste, vous n'avez donc pas besoin de l'option list() mais les versions ultérieures renvoient un objet de vue dictionnaire Vous le ferez.

Edit : Comme indiqué dans les commentaires, l'opération la plus rapide est à faire :

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

Bien que je doive admettre que je trouve cela plus laid dans le code (je n'ai jamais aimé obtenir la clé puis faire x[key] pour obtenir la valeur séparément, je préfère obtenir la valeur du (key, value) tuple) - en fonction de l'importance de la vitesse et de vos préférences, vous pouvez choisir la première option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X