web-dev-qa-db-fra.com

Dernier élément dans OrderedDict

J'ai od de type OrderedDict. Je souhaite accéder à sa dernière paire (clé, valeur) ajoutée. od.popitem(last = True) le ferait, mais supprimerait également la paire de od dont je ne veux pas.

Quelle est la bonne façon de procéder? Puis-je/dois-je faire ceci:

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

L'utilisation de 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 implémente __reversed__() , donc cette implémentation vous donne O(1) accès à l'élément souhaité. La pertinence de la sous-classe OrderedDict() pour cette opération simple peut être remise en question, mais il n'y a rien de mal à cette approche.

62
Sven Marnach

Un peu de magie du temps 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())

résulte en:

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 façons dont je pourrais cuisiner.

15
mgilson

Dieu, je souhaite que ce soit toutes les fonctionnalités intégrées ...

Voici quelque chose pour vous faire gagner un temps précieux. Testé en Python 3.7. od est votre OrderedDict.


# Get first key
next(iter(od.keys()))

# Get last key
next(reversed(od.keys()))

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

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

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

# Get last key-value Tuple
next(reversed(od.items()))
3
Hubert Grzeskowiak

Votre idée est bonne, mais l'itérateur par défaut est uniquement sur les clés, donc votre exemple ne retournera que la dernière clé. Ce que vous voulez vraiment, c'est:

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

Cela donne les paires (key, value), Pas seulement les clés, comme vous le vouliez.

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

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

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

Bien que je dois 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 le tuple (key, value)) - selon l'importance de vitesse et vos préférences, vous pouvez choisir l'ancienne option.

2
Gareth Latty