OrderedDict Isn't Ordered?

Question:

I’m trying to use an OrderedDict, but it keeps being created out of order. For example,

from collections import OrderedDict
OrderedDict(a=1,b=2,c=3)

yields

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

rather than the expected

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

How can I make sure it’s created in the proper order I intend?

Asked By: wogsland

||

Answers:

That is because the keyword arguments (variable = value, ) that you pass will be consolidated into a Python dictionary first. And Python dictionaries are unordered. kwds will be that dictionary as you can see in the Init signature.

Init signature: OrderedDict(self, *args, **kwds)

This is how the OrderedDict will be initialized internally when you pass the keyword arguments:

for key, value in kwds.items():
   self[key] = value

Since kwds is unordered, you will get an unordered OrderedDict.

You may create the ordered dict like so:

from collections import OrderedDict
from string import ascii_lowercase

d = OrderedDict()
for a,b in enumerate(ascii_lowercase[:3], 1):
    d[b] = a

Or:

n=3
d = OrderedDict(zip(ascii_lowercase[:n], range(1,n+1))) 
print d 

Output:

OrderedDict([('a', 1), ('b', 2), ('c', 3)])
Answered By: Mohammad Yusuf

Read the docs:

The OrderedDict constructor and update() method both accept keyword arguments, but their order is lost because Python’s function call semantics pass-in keyword arguments using a regular unordered dictionary.

You must pass the input as a sequence of tuples (or an existing ordered dict type) to preserve ordering.

Note that Python 3.6 now provides a guarantee that keyword arguments are passed in the same order they appear in the code (from left to right), thanks to PEP 468, so on Python 3.6 and later, your code will just work.

Answered By: ShadowRanger

collections.OrderedDict keeps track of the order in which elements were added to it. This would work fine in a loop:

c = collections.OrderedDict()
for a,b in zip('abc', (1,2,3)):
    c[a] = b

However, the expression OrderedDict(a=1,b=2,c=3) creates an OrderedDict by passing several keyword arguments to its constructor. In Python 2.7, the order of keyword arguments is not guaranteed. If you want that, you’ll have to move to Python 3.6, which implements PEP 468, Preserving the order of **kwargs in a function.

The **kwargs syntax in a function definition indicates that the interpreter should collect all keyword arguments that do not correspond to other named parameters. However, Python does not preserved the order in which those collected keyword arguments were passed to the function. In some contexts the order matters. This PEP dictates that the collected keyword arguments be exposed in the function body as an ordered mapping.

Answered By: TigerhawkT3

You can create the desired mapping by using sorted():

dict = {"a":"some_value", "b":"other_value", "c":"foo"}
ordered = OrderedDict(sorted(dict.items(), key=lambda t: t[0]))

This sorts the items prior to passing them to the OrderedDict constructor.

The key= section sets the sorting, and t[0] sorts by the dictionary key.

Answered By: Andrakis

It’s weird that it hasn’t been mentioned already but the representation of OrderedDict shows you how to create it so that the order is kept:

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

it’s not meant as an obstacle that the representation is like that – it’s because that representation can be used to create an identical ordered OrderedDict.


Just for completeness (it has been mentioned already), the order is lost because OrderedDict(a=1, b=2, c=3) catches these arguments as **kwargs, which is a normal unordered-dict. At least until python 3.6 came along and made the promise that the order of the kwargs will be kept when you pass it in as you did:

What’s New In Python 3.6

PEP 468: Preserving Keyword Argument Order

**kwargs in a function signature is now guaranteed to be an insertion-order-preserving mapping.

Answered By: MSeifert
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.