Последний элемент в OrderedDict - PullRequest
34 голосов
/ 29 марта 2012

У меня od типа OrderedDict. Я хочу получить доступ к его самой последней добавленной паре (ключ, значение). od.popitem(last = True) сделает это, но также удалит пару из od, которую я не хочу.

Какой хороший способ сделать это? Могу ли я сделать это:

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

Ответы [ 4 ]

54 голосов
/ 29 марта 2012

Использование next(reversed(od)) - идеальный способ доступа к недавно добавленному элементу. Класс OrderedDict использует двусвязный список для элементов словаря и реализует __reversed__(), поэтому эта реализация дает O (1) доступ к нужному элементу. Вопрос о целесообразности подкласса OrderedDict() для этой простой операции может быть поставлен под сомнение, но в этом подходе нет ничего плохого.

15 голосов
/ 29 марта 2012

Немного магии времени может помочь здесь ...

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

приводит к:

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

(протестировано на python3.2, Ubuntu Linux).

Как указал @SvenMarnach, описанный вами метод довольно эффективен по сравнению с двумя другими способами, которые я мог бы приготовить.

2 голосов
/ 29 марта 2012

Ваша идея в порядке, однако итератор по умолчанию работает только над ключами, поэтому ваш пример вернет только последний ключ. На самом деле вы хотите:

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

Это дает пары (key, value), а не только ключи, как вы хотели.

Обратите внимание, что в версиях Python до 3.x OrderedDict.items() возвращает список, поэтому вам не нужен вызов list(), но более поздние версии возвращают объект представления словаря , поэтому вы будете.

Редактировать: Как отмечено в комментариях, более быстрая операция должна сделать:

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

Хотя я должен признать, что нахожу это уродливым в коде (мне никогда не нравилось получать ключ, тогда я делал x[key], чтобы получить значение отдельно, я предпочитаю получать кортеж (key, value)) - в зависимости от важности ваши предпочтения, вы можете выбрать первый вариант.

0 голосов
/ 01 июля 2019

Боже, я бы хотел, чтобы все это было встроенным функционалом ...

Вот кое-что, чтобы сэкономить ваше драгоценное время.Протестировано в Python 3.7.od ваш заказ.


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