Последний элемент в OrderedDict
У меня od
типа OrderedDict
. Я хочу получить доступ к его последней добавленной (ключевой, значащей) паре. od.popitem(last = True)
сделает это, но также удалит пару из od
, которую я не хочу.
Какой хороший способ сделать это? Могу/должен ли я это сделать:
class MyOrderedDict(OrderedDict):
def last(self):
return next(reversed(self))
Ответы
Ответ 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()))