我怎样才能在python的OrderedDict的顶部添加一个元素?

我有这个

d1 = OrderedDict([('a', '1'), ('b', '2')]) 

如果我这样做

d1.update({'c':'3'})

然后我得到这个

OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])

但我想要这个

 [('c', '3'), ('a', '1'), ('b', '2')] 

无需创build新的字典

在Python 2中没有内置的方法。如果你需要这样的话,你需要编写一个prepend()方法/函数来处理O(1)复杂的OrderedDict内部函数。

对于Python 3.2及更高版本,您可以使用move_to_end 1方法。 该方法接受last参数,该参数指示元素是被移动到OrderedDict的底部( last=True )还是顶部( last=False )。

最后,如果你想要一个快速,肮脏和缓慢的解决scheme,你可以从头开始创build一个新的OrderedDict

四种不同解决scheme的详细信息:


扩展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对象的独立函数

这个函数通过接受字典对象,键和值来做同样的事情。 我个人比较喜欢这个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)

1 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')]) 

如果我们需要插入一个元素并将其移动到顶部,那么我们可以直接使用它来创build一个prepend()包装器(这里没有提供)。


创build一个新的OrderedDict – 慢!

如果你不想这样做, 性能不是问题,那么最简单的方法是创build一个新的字典:

 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') --> ABCD # unique_everseen('ABBCcAD', str.lower) --> ABCD 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写了一个子类,用于类似的目的。 这是要点 。

插入操作也是恒定的时间O(1) (它们不需要重build数据结构),这与大多数解决scheme不同。

 >>> d1 = ListDict([('a', '1'), ('b', '2')]) >>> d1.insert_before('a', ('c', 3)) >>> d1 ListDict([('c', 3), ('a', '1'), ('b', '2')]) 

你必须创build一个OrderedDict的新实例。 如果你的密钥是唯一的:

 d1=OrderedDict([("a",1),("b",2)]) d2=OrderedDict([("c",3),("d",99)]) both=OrderedDict(list(d2.items()) + list(d1.items())) print(both) #OrderedDict([('c', 3), ('d', 99), ('a', 1), ('b', 2)]) 

但是,如果没有,请注意这种行为可能会或可能不会被你想要:

 d1=OrderedDict([("a",1),("b",2)]) d2=OrderedDict([("c",3),("b",99)]) both=OrderedDict(list(d2.items()) + list(d1.items())) print(both) #OrderedDict([('c', 3), ('b', 2), ('a', 1)]) 

如果你知道你会想要一个'c'键,但是不知道这个值,当你创build字典的时候,用一个虚拟值插入'c'。

 d1 = OrderedDict([('c', None), ('a', '1'), ('b', '2')]) 

并稍后更改值。

 d1['c'] = 3 

现在可以使用move_to_end(key,last = True)

 >>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d.keys()) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d.keys()) 'bacde' 

https://docs.python.org/3/library/collections.html#collections.OrderedDict.move_to_end

如果你需要不在那里的function,只要用你想要的任何东西来扩展这个类:

 from collections import OrderedDict class OrderedDictWithPrepend(OrderedDict): def prepend(self, other): ins = [] if hasattr(other, 'viewitems'): other = other.viewitems() for key, val in other: if key in self: self[key] = val else: ins.append((key, val)) if ins: items = self.items() self.clear() self.update(ins) self.update(items) 

不是非常有效,但工作:

 o = OrderedDictWithPrepend() o['a'] = 1 o['b'] = 2 print o # OrderedDictWithPrepend([('a', 1), ('b', 2)]) o.prepend({'c': 3}) print o # OrderedDictWithPrepend([('c', 3), ('a', 1), ('b', 2)]) o.prepend([('a',11),('d',55),('e',66)]) print o # OrderedDictWithPrepend([('d', 55), ('e', 66), ('c', 3), ('a', 11), ('b', 2)]) 

我会build议在这个纯Python的配方中添加一个prepend()方法或者从中派生一个子类。 这样做的代码可能是相当有效的,因为sorting的基础数据结构是一个链表。