Подтвердить что ты не робот

Последний элемент в OrderedDict

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

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

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

Ответ 1

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

Ответ 2

Маленькая магия от timeit может помочь здесь...

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, описанный вами метод довольно эффективен по сравнению с двумя другими способами, которые я мог бы приготовить.

Ответ 3

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

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)) - в зависимости от важности скорости и ваши предпочтения, вы можете выбрать прежний вариант.

Ответ 4

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

Здесь что-то, чтобы сэкономить ваше драгоценное время. Протестировано в 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()))