У Python 2 для цього не існує вбудованого методу. Якщо вам це потрібно, вам потрібно написати prepend()
метод / функцію, яка працює на OrderedDict
внутрішніх елементах зі складністю O (1).
Для Python 3.2 і пізніших версій вам слід використовувати move_to_end
метод. Метод приймає last
аргумент, який вказує, чи буде елемент переміщено до нижньої ( last=True
) чи верхньої ( last=False
) частини OrderedDict
.
Нарешті, якщо ви хочете швидке, брудне і повільне рішення, ви можете просто створити нове OrderedDict
з нуля.
Деталі чотирьох різних рішень:
Розширте OrderedDict
та додайте новий метод екземпляра
from collections import OrderedDict
class MyOrderedDict(OrderedDict):
def prepend(self, key, value, dict_setitem=dict.__setitem__):
root = self._OrderedDict__root
first = root[1]
if key in self:
link = self._OrderedDict__map[key]
link_prev, link_next, _ = link
link_prev[1] = link_next
link_next[0] = link_prev
link[0] = root
link[1] = first
root[1] = first[0] = link
else:
root[1] = first[0] = self._OrderedDict__map[key] = [root, first, key]
dict_setitem(self, key, value)
Демо:
>>> d = MyOrderedDict([('a', '1'), ('b', '2')])
>>> d
MyOrderedDict([('a', '1'), ('b', '2')])
>>> d.prepend('c', 100)
>>> d
MyOrderedDict([('c', 100), ('a', '1'), ('b', '2')])
>>> d.prepend('a', d['a'])
>>> d
MyOrderedDict([('a', '1'), ('c', 100), ('b', '2')])
>>> d.prepend('d', 200)
>>> d
MyOrderedDict([('d', 200), ('a', '1'), ('c', 100), ('b', '2')])
Автономна функція, яка маніпулює OrderedDict
об’єктами
Ця функція робить те саме, приймаючи об'єкт, ключ і значення dict. Я особисто віддаю перевагу заняттям:
from collections import OrderedDict
def ordered_dict_prepend(dct, key, value, dict_setitem=dict.__setitem__):
root = dct._OrderedDict__root
first = root[1]
if key in dct:
link = dct._OrderedDict__map[key]
link_prev, link_next, _ = link
link_prev[1] = link_next
link_next[0] = link_prev
link[0] = root
link[1] = first
root[1] = first[0] = link
else:
root[1] = first[0] = dct._OrderedDict__map[key] = [root, first, key]
dict_setitem(dct, key, value)
Демо:
>>> d = OrderedDict([('a', '1'), ('b', '2')])
>>> ordered_dict_prepend(d, 'c', 100)
>>> d
OrderedDict([('c', 100), ('a', '1'), ('b', '2')])
>>> ordered_dict_prepend(d, 'a', d['a'])
>>> d
OrderedDict([('a', '1'), ('c', 100), ('b', '2')])
>>> ordered_dict_prepend(d, 'd', 500)
>>> d
OrderedDict([('d', 500), ('a', '1'), ('c', 100), ('b', '2')])
Використання OrderedDict.move_to_end()
(Python> = 3.2)
Python 3.2 введений в OrderedDict.move_to_end()
метод. Використовуючи його, ми можемо перемістити існуючий ключ до будь-якого кінця словника за час O (1).
>>> d1 = OrderedDict([('a', '1'), ('b', '2')])
>>> d1.update({'c':'3'})
>>> d1.move_to_end('c', last=False)
>>> d1
OrderedDict([('c', '3'), ('a', '1'), ('b', '2')])
Якщо нам потрібно вставити елемент і перемістити його вгору, все за один крок, ми можемо безпосередньо використовувати його для створення prepend()
обгортки (тут не представлено).
Створити нову OrderedDict
- повільно !!!
Якщо ви не хочете цього робити, і продуктивність не є проблемою, то найпростіший спосіб - створити новий дикт:
from itertools import chain, ifilterfalse
from collections import OrderedDict
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
d1 = OrderedDict([('a', '1'), ('b', '2'),('c', 4)])
d2 = OrderedDict([('c', 3), ('e', 5)])
new_dic = OrderedDict((k, d2.get(k, d1.get(k))) for k in \
unique_everseen(chain(d2, d1)))
print new_dic
вихід:
OrderedDict([('c', 3), ('e', 5), ('a', '1'), ('b', '2')])