在 Python 2 中没有用于执行此操作的内置方法。如果需要,您需要编写一个 prepend() 方法/函数,该方法/函数在 OrderedDict 内部进行操作,复杂度为 O(1)。
对于 Python 3.2 及更高版本,您应该使用move_to_end 方法。该方法接受一个last 参数,该参数指示元素将被移动到OrderedDict 的底部(last=True)还是顶部(last=False)。
最后,如果您想要一个快速、肮脏和缓慢的解决方案,您可以从头开始创建一个新的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 introduced 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."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
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)]) #dict containing items to be added at the front
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')])