Reputation: 9508
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?
Upvotes: 32
Views: 10900
Reputation: 155363
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.
Upvotes: 13
Reputation: 152637
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.
Upvotes: 19
Reputation: 167
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.
Upvotes: 1
Reputation: 17064
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)])
Upvotes: 3
Reputation: 49318
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.
Upvotes: 57