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

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