How to add an element to the beginning of an OrderedDict? How to add an element to the beginning of an OrderedDict? python-3.x python-3.x

How to add an element to the beginning of an OrderedDict?


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.

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.

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:


Extend OrderedDict and add a new instance method

from collections import OrderedDictclass 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)

Demo:

>>> d = MyOrderedDict([('a', '1'), ('b', '2')])>>> dMyOrderedDict([('a', '1'), ('b', '2')])>>> d.prepend('c', 100)>>> dMyOrderedDict([('c', 100), ('a', '1'), ('b', '2')])>>> d.prepend('a', d['a'])>>> dMyOrderedDict([('a', '1'), ('c', 100), ('b', '2')])>>> d.prepend('d', 200)>>> dMyOrderedDict([('d', 200), ('a', '1'), ('c', 100), ('b', '2')])

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 OrderedDictdef 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)

Demo:

>>> d = OrderedDict([('a', '1'), ('b', '2')])>>> ordered_dict_prepend(d, 'c', 100)>>> dOrderedDict([('c', 100), ('a', '1'), ('b', '2')])>>> ordered_dict_prepend(d, 'a', d['a'])>>> dOrderedDict([('a', '1'), ('c', 100), ('b', '2')])>>> ordered_dict_prepend(d, 'd', 500)>>> dOrderedDict([('d', 500), ('a', '1'), ('c', 100), ('b', '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)>>> d1OrderedDict([('c', '3'), ('a', '1'), ('b', '2')])

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).


Create a new OrderedDict - slow!!!

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, ifilterfalsefrom collections import OrderedDictdef 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 elementd1 = OrderedDict([('a', '1'), ('b', '2'),('c', 4)])d2 = OrderedDict([('c', 3), ('e', 5)])   #dict containing items to be added at the frontnew_dic = OrderedDict((k, d2.get(k, d1.get(k))) for k in \                                           unique_everseen(chain(d2, d1)))print new_dic

output:

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


EDIT (2019-02-03)Note that the following answer only works on older versions of Python. More recently, OrderedDict has been rewritten in C. In addition this does touch double-underscore attributes which is frowned upon.

I just wrote a subclass of OrderedDict in a project of mine for a similar purpose. Here's the gist.

Insertion operations are also constant time O(1) (they don't require you to rebuild the data structure), unlike most of these solutions.

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


You have to make a new instance of OrderedDict. If your keys are unique:

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

But if not, beware as this behavior may or may not be desired for you:

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