如何在OrderedDict的开头添加元素? [英] How to add an element to the beginning of an OrderedDict?
问题描述
我有这个:
d1 = OrderedDict([('a', '1'), ('b', '2')])
如果我这样做:
d1.update({'c':'3'})
然后我得到了:
OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
但是我想要这个:
[('c', '3'), ('a', '1'), ('b', '2')]
无需创建新词典.
推荐答案
在Python 2中没有内置方法可以执行此操作. OrderedDict
内部结构复杂度为O(1).
There's no built-in method for doing this in Python 2. If you need this, you need to write a prepend()
method/function that operates on the OrderedDict
internals with O(1) complexity.
对于Python 3.2和更高版本,您应使用 move_to_end
方法.该方法接受last
参数,该参数指示元素将被移动到OrderedDict
的底部(last=True
)还是顶部(last=False
).
For Python 3.2 and later, you should use the move_to_end
method. The method accepts a last
argument which indicates whether the element will be moved to the bottom (last=True
) or the top (last=False
) of the OrderedDict
.
最后,如果您想要一种快速,肮脏且缓慢的解决方案,则可以从头开始创建一个新的OrderedDict
.
Finally, if you want a quick, dirty and slow solution, you can just create a new OrderedDict
from scratch.
四种不同解决方案的详细信息:
Details for the four different solutions:
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对象,键和值来执行相同的操作.我个人更喜欢上课:
Standalone function that manipulates OrderedDict
objects
This function does the same thing by accepting the dict object, key and value. I personally prefer the class:
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)
Use OrderedDict.move_to_end()
(Python >= 3.2)
Python 3.2 introduced the OrderedDict.move_to_end()
method. Using it, we can move an existing key to either end of the dictionary in O(1) time.
>>> 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()
包装器(此处未显示).
If we need to insert an element and move it to the top, all in one step, we can directly use it to create a prepend()
wrapper (not presented here).
如果您不想这样做,并且性能不是问题,那么最简单的方法是创建一个新的字典:
If you don't want to do that and performance is not an issue then easiest way is to create a new dict:
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')])
这篇关于如何在OrderedDict的开头添加元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!