[python] sorting dictionary python 3

I'm working on python 3.2.2. Breaking my head more than 3 hours to sort a dictionary by it's keys. I managed to make it a sorted list with 2 argument members, but can not make it a sorted dictionary in the end.

This is what I've figured:

myDic={10: 'b', 3:'a', 5:'c'}
sorted_list=sorted(myDic.items(), key=lambda x: x[0])

But no matter what I can not make a dictionary out of this sorted list. How do I do that? Thanks!

This question is related to python dictionary

The answer is


Maybe not that good but I've figured this:

def order_dic(dic):
    ordered_dic={}
    key_ls=sorted(dic.keys())
    for key in key_ls:
        ordered_dic[key]=dic[key]
    return ordered_dic

Any modern solution to this problem? I worked around it with:

    order = sorted([ job['priority'] for job in self.joblist ])
    sorted_joblist = []
    while order:
        min_priority = min(order)
        for job in self.joblist:
            if job['priority'] == min_priority:
                sorted_joblist += [ job ]
                order.remove(min_priority)
    self.joblist = sorted_joblist

The joblist is formatted as: joblist = [ { 'priority' : 3, 'name' : 'foo', ... }, { 'priority' : 1, 'name' : 'bar', ... } ]

  • Basically I create a list (order) with all the elements by which I want to sort the dict
  • then I iterate this list and the dict, when I find the item on the dict I send it to a new dict and remove the item from 'order'.

Seems to be working, but I suppose there are better solutions.


Python's ordinary dicts cannot be made to provide the keys/elements in any specific order. For that, you could use the OrderedDict type from the collections module. Note that the OrderedDict type merely keeps a record of insertion order. You would have to sort the entries prior to initializing the dictionary if you want subsequent views/iterators to return the elements in order every time. For example:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sorted_list=sorted(myDic.items(), key=lambda x: x[0])
>>> myOrdDic = OrderedDict(sorted_list)
>>> myOrdDic.items()
[(3, 'a'), (5, 'c'), (10, 'b')]
>>> myOrdDic[7] = 'd'
>>> myOrdDic.items()
[(3, 'a'), (5, 'c'), (10, 'b'), (7, 'd')]

If you want to maintain proper ordering for newly added items, you really need to use a different data structure, e.g., a binary tree/heap. This approach of building a sorted list and using it to initialize a new OrderedDict() instance is just woefully inefficient unless your data is completely static.

Edit: So, if the object of sorting the data is merely to print it in order, in a format resembling a python dict object, something like the following should suffice:

def pprint_dict(d):
    strings = []
    for k in sorted(d.iterkeys()):
        strings.append("%d: '%s'" % (k, d[k]))
    return '{' + ', '.join(strings) + '}'

Note that this function is not flexible w/r/t the types of the key, value pairs (i.e., it expects the keys to be integers and the corresponding values to be strings). If you need more flexibility, use something like strings.append("%s: %s" % (repr(k), repr(d[k]))) instead.


Sorting dictionaries by value using comprehensions. I think it's nice as 1 line and no need for functions or lambdas

a = {'b':'foo', 'c':'bar', 'e': 'baz'}
a = {f:a[f] for f in sorted(a, key=a.__getitem__)}

I'm not sure whether this could help, but I had a similar problem and I managed to solve it, by defining an apposite function:

def sor_dic_key(diction):
    lista = []
    diction2 = {}
    for x in diction:
        lista.append([x, diction[x]])
    lista.sort(key=lambda x: x[0])
    for l in lista:
        diction2[l[0]] = l[1]
    return diction2

This function returns another dictionary with the same keys and relative values, but sorted by its keys. Similarly, I defined a function that could sort a dictionary by its values. I just needed to use x[1] instead of x[0] in the lambda function. I find this second function mostly useless, but one never can tell!


A modern and fast solution, for Python 3.7. May also work in some interpreters of Python 3.6.

TLDR

To sort a dictionary by keys use:

sorted_dict = {k: disordered[k] for k in sorted(disordered)}

Almost three times faster than the accepted answer; probably more when you include imports.

Comment on the accepted answer

The example in the accepted answer instead of iterating over the keys only - with key parameter of sorted() or the default behaviour of dict iteration - iterates over tuples (key, value), which suprisingly turns out to be much slower than comparing the keys only and accessing dictionary elements in a list comprehension.

How to sort by key in Python 3.7

The big change in Python 3.7 is that the dictionaries are now ordered by default.

  • You can generate sorted dict using dict comprehensions.
  • Using OrderedDict might still be preferable for the compatibility sake.
  • Do not use sorted(d.items()) without key.

See:

disordered = {10: 'b', 3: 'a', 5: 'c'}

# sort keys, then get values from original - fast
sorted_dict = {k: disordered[k] for k in sorted(disordered)}

# key = itemgetter - slower
from operator import itemgetter
key = itemgetter(0)
sorted_dict = {k: v for k, v in sorted(disordered.items(), key=key)}

# key = lambda - the slowest
key = lambda item: item[0]
sorted_dict = {k: v for k in sorted(disordered.items(), key=key)} 

Timing results:

Best for {k: d[k] for k in sorted(d)}: 7.507327548999456
Best for {k: v for k, v in sorted(d.items(), key=key_getter)}: 12.031082626002899
Best for {k: v for k, v in sorted(d.items(), key=key_lambda)}: 14.22885995300021

Best for dict(sorted(d.items(), key=key_getter)): 11.209122000000207
Best for dict(sorted(d.items(), key=key_lambda)): 13.289728325995384
Best for dict(sorted(d.items())): 14.231471302999125

Best for OrderedDict(sorted(d.items(), key=key_getter)): 16.609151654003654
Best for OrderedDict(sorted(d.items(), key=key_lambda)): 18.52622927199991
Best for OrderedDict(sorted(d.items())): 19.436101284998585

Testing code:

from timeit import repeat

setup_code = """
from operator import itemgetter
from collections import OrderedDict
import random
random.seed(0)
d = {i: chr(i) for i in [random.randint(0, 120) for repeat in range(120)]}
key_getter = itemgetter(0)
key_lambda = lambda item: item[0]
"""

cases = [
    # fast
    '{k: d[k] for k in sorted(d)}',
    '{k: v for k, v in sorted(d.items(), key=key_getter)}',
    '{k: v for k, v in sorted(d.items(), key=key_lambda)}',
    # slower
    'dict(sorted(d.items(), key=key_getter))',
    'dict(sorted(d.items(), key=key_lambda))',
    'dict(sorted(d.items()))',
    # the slowest 
    'OrderedDict(sorted(d.items(), key=key_getter))',
    'OrderedDict(sorted(d.items(), key=key_lambda))',
    'OrderedDict(sorted(d.items()))',
]

for code in cases:
    times = repeat(code, setup=setup_code, repeat=3)
    print(f"Best for {code}: {min(times)}")

With Python 3.7 I could do this:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sortDic = sorted(myDic.items())
>>> print(dict(sortDic))
{3:'a', 5:'c', 10: 'b'}

If you want a list of tuples:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sortDic = sorted(myDic.items())
>>> print(sortDic)
[(3, 'a'), (5, 'c'), (10, 'b')]

I don't think you want an OrderedDict. It sounds like you'd prefer a SortedDict, that is a dict that maintains its keys in sorted order. The sortedcontainers module provides just such a data type. It's written in pure-Python, fast-as-C implementations, has 100% coverage and hours of stress.

Installation is easy with pip:

pip install sortedcontainers

Note that if you can't pip install then you can simply pull the source files from the open-source repository.

Then you're code is simply:

from sortedcontainers import SortedDict
myDic = SortedDict({10: 'b', 3:'a', 5:'c'})
sorted_list = list(myDic.keys())

The sortedcontainers module also maintains a performance comparison with other popular implementations.


Dictionaries are unordered by definition, What would be the main reason for ordering by key? A list of tuples created by the sort method can be used for whatever the need may have been, but changing the list of tuples back into a dictionary will return a random order

>>> myDic
{10: 'b', 3: 'a', 5: 'c'}
>>> sorted(myDic.items())
[(3, 'a'), (5, 'c'), (10, 'b')]
>>> print(dict(myDic.items()))
{10: 'b', 3: 'a', 5: 'c'}

The accepted answer definitely works, but somehow miss an important point.

The OP is asking for a dictionary sorted by it's keys this is just not really possible and not what OrderedDict is doing.

OrderedDict is maintaining the content of the dictionary in insertion order. First item inserted, second item inserted, etc.

>>> d = OrderedDict()
>>> d['foo'] = 1
>>> d['bar'] = 2
>>> d
OrderedDict([('foo', 1), ('bar', 2)])

>>> d = OrderedDict()
>>> d['bar'] = 2
>>> d['foo'] = 1
>>> d
OrderedDict([('bar', 2), ('foo', 1)])

Hencefore I won't really be able to sort the dictionary inplace, but merely to create a new dictionary where insertion order match key order. This is explicit in the accepted answer where the new dictionary is b.

This may be important if you are keeping access to dictionaries through containers. This is also important if you itend to change the dictionary later by adding or removing items: they won't be inserted in key order but at the end of dictionary.

>>> d = OrderedDict({'foo': 5, 'bar': 8})
>>> d
OrderedDict([('foo', 5), ('bar', 8)])
>>> d['alpha'] = 2
>>> d
OrderedDict([('foo', 5), ('bar', 8), ('alpha', 2)])

Now, what does mean having a dictionary sorted by it's keys ? That makes no difference when accessing elements by keys, this only matter when you are iterating over items. Making that a property of the dictionary itself seems like overkill. In many cases it's enough to sort keys() when iterating.

That means that it's equivalent to do:

>>> d = {'foo': 5, 'bar': 8}
>>> for k,v in d.iteritems(): print k, v

on an hypothetical sorted by key dictionary or:

>>> d = {'foo': 5, 'bar': 8}
>>> for k, v in iter((k, d[k]) for k in sorted(d.keys())): print k, v

Of course it is not hard to wrap that behavior in an object by overloading iterators and maintaining a sorted keys list. But it is likely overkill.


I like python numpy for this kind of stuff! eg:

r=readData()
nsorted = np.lexsort((r.calls, r.slow_requests, r.very_slow_requests, r.stalled_requests))

I have an example of importing CSV data into a numpy and ordering by column priorities. https://github.com/unixunion/toolbox/blob/master/python/csv-numpy.py

Kegan