ChatGPT解决这个技术问题 Extra ChatGPT

How can I sort a dictionary by key?

How do I sort a dictionary by its keys?

Example input:

{2:3, 1:89, 4:5, 3:0}

Desired output:

{1:89, 2:3, 3:0, 4:5}
@KarlKnechtel - my use case is that I have a CLI application that has a primitive menu and the menu options are in a dictionary as the keys. I would like to display the keys alphabetically for user sanity.
@Nayuki, given that this is a Python question I was equating dictionary with dict
Note that dicts are now ordered by insertion order (python 3.6+). Some answers below point this.
@matiasg note that in Python 3.6, insertion-order preserving dicts are an implementation detail of CPython. It is with Python 3.7 that the insertion-order preservation of dicts become officially part of the language

S
SuperStormer

Note: for Python 3.7+, see this answer

Standard Python dictionaries are unordered (until Python 3.7). Even if you sorted the (key,value) pairs, you wouldn't be able to store them in a dict in a way that would preserve the ordering.

The easiest way is to use OrderedDict, which remembers the order in which the elements have been inserted:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

Never mind the way od is printed out; it'll work as expected:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

For Python 3 users, one needs to use the .items() instead of .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5

@achrysochoou: if that worked, it must have been by sheer luck. As you've been told, regular dictionaries have no concept of sorting, no matter if you assign the keys sorted or in random way.
For python 3.7+: sorted_dict = dict(sorted(unsorted_dict.items()))
python 3.7+ shouldn't need orderedDict since it now orders by default :-)
From python 3.7.4 manual: "Performing list(d) on a dictionary returns a list of all the keys used in the dictionary, in insertion order". So insertion order is something which is preserved and we can rely on.
OrderedDict is a half-solution because it maintains the order of insertion. Therefore, one cannot start from an empty dictionary and add items and expect the keys to be in sorted order. Rather, it can only be used on an existing dictionary after all items have been populated since the OrderedDict structure works only on order of insertion and not any kind of sorting you might expect.
N
Nils von Barth

Dictionaries themselves do not have ordered items as such, should you want to print them etc to some order, here are some examples:

In Python 2.4 and above:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

for key in sorted(mydict):
    print "%s: %s" % (key, mydict[key])

gives:

alan: 2
bob: 1
carl: 40
danny: 3

(Python below 2.4:)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Source: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/


You can also use OrderedDict in python 2.4+ as in NPE's answer
and if you're using items() you can do it like for key, value in sorted(mydict.items())"
Dictionaries themselves do not have ordered items as such -> no longer true!
How come, can you explain?
@James See link.
S
ShadowRanger

For CPython/PyPy 3.6, and any Python 3.7 or higher, this is easily done with:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}

Another way of writing the same thing is use a comprehension: {key:d[key] for key in sorted(d.keys())}
Great oneliner! I didn't know about that new feature. It works for me in Centos 7 on Python 3.6.8.
This is a great answer. But don't try to make it shorter by enclosing sorted with {} as in {sorted(d.items())}. That will just try to create a set.
The answer by @flow2k (using "comprehension") can be simplified: {key:d[key] for key in sorted(d)} since sorted(d) returns a sorted list of d's keys
@Timo sorted(d.items()) returns an iterable to the sorted key & value pair, not a dictionary
D
Dennis

From Python's collections library documentation:

>>> from collections import OrderedDict

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

awesome! Guys if you want to reverse the order (ascending TO descending) then you simply add reverse=True e.g. OrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
In PyCharm, no matter what dictionary I use, I always get this warning: Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
G
GrantJ

There are a number of Python modules that provide dictionary implementations which automatically maintain the keys in sorted order. Consider the sortedcontainers module which is pure-Python and fast-as-C implementations. There is also a performance comparison with other popular options benchmarked against one another.

Using an ordered dict is an inadequate solution if you need to constantly add and remove key/value pairs while also iterating.

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

The SortedDict type also supports indexed location lookups and deletion which isn't possible with the built-in dict type.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])

u
user3769249

Simply:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Output:

1 89
2 3
3 0
4 5

sd is a list of tuples, not a dictionary. (still useful though.)
I believe your print statement needs (). print (k,v)
You only need () for python 3. print k, v works just fine in python 2 because print is a keyword, not a function in python 2.
G
Guangyang Li

Python dictionary was unordered before Python 3.6. In CPython implementation of Python 3.6, dictionary keeps the insertion order. From Python 3.7, this will become a language feature.

In changelog of Python 3.6 (https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict):

The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5).

In document of Python 3.7 (https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries):

Performing list(d) on a dictionary returns a list of all the keys used in the dictionary, in insertion order (if you want it sorted, just use sorted(d) instead).

So unlike previous versions, you can sort a dict after Python 3.6/3.7. If you want to sort a nested dict including the sub-dict inside, you can do:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: dict_reoder(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb


I like this, but you have sort_dict() in your dictionary comprehension that should probably be dict_reoder()
B
Brian

As others have mentioned, dictionaries are inherently unordered. However, if the issue is merely displaying dictionaries in an ordered fashion, you can override the __str__ method in a dictionary subclass, and use this dictionary class rather than the builtin dict. Eg.

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Note, this changes nothing about how the keys are stored, the order they will come back when you iterate over them etc, just how they're displayed with print or at the python console.


t
tschesseket

Found another way:

import json
print json.dumps(d, sort_keys = True)

upd: 1. this also sorts nested objects (thanks @DanielF). 2. python dictionaries are unordered therefore this is sutable for print or assign to str only.


But this also sorts the keys of nested objects, which might not be wanted.
Note that this only sorts dictionaries, not lists, e.g. dict.keys() will not be sorted because it is a list.
E
Evgeny Tryastsin

In Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

gives

1 89
2 3
3 0
4 5

p
pr94

An easy way to do this:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 

Works only for python 3.7+, where dict is an OrderedDict.
@kwarnke Pedantic, but dict is not the same as OrderedDict in Python 3.7+, although dict is of course ordered in 3.7+
a
alphazwest

There are plenty of answers here already showcasing popular ways to sort a Python dictionary. I thought I'd add a few more less-obvious ways for those coming here from Google looking for non-standard ideas.

Sample Dictionary: d = {2: 'c', 1: 'b', 0: 'a', 3: 'd'}

Dictionary Comprehension

# Converts to list, sorts, re-converts to dict
{k: v for k, v in sorted(list(d.items()))}

Using Lambdas

Sorting isn't always intended to order strictly in ascending or descending order. For more conditional sorting, use the above method combined with lamdas:

{k: v for k, v in sorted(d.items(), key=lambda v: ord(v[1]))}

More Examples

This thread is already full enough of good examples. For some more examples, as well as edge-cases and oddities check out this article on sorting dictionaries in Python.


For the dictionary list comprehension, it doesnt work for me I need to replace sorted(list(d)) by sorted(d.items()) (on python 3.8)
@ihoupert It wasn't just you. I should have just copy/pasted my version rather than trying to type it out fresh. It definitely needs the .items() call there.
I had a similar issue. I had to use .items() thanks to @ihoupert
P
Pang

You can create a new dictionary by sorting the current dictionary by key as per your question.

This is your dictionary

d = {2:3, 1:89, 4:5, 3:0}

Create a new dictionary d1 by sorting this d using lambda function

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 should be {1: 89, 2: 3, 3: 0, 4: 5}, sorted based on keys in d.


You don't even need to specify the sort key. d1 = dict(sorted(d.items())) will work just fine
Why is this not the best answer?
A
Atul Arvind

Here I found some simplest solution to sort the python dict by key using pprint. eg.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

but while using pprint it will return sorted dict

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}

S
Sree

There is an easy way to sort a dictionary.

According to your question,

The solution is :

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Where c,is the name of your dictionary.)

This program gives the following output:

[(1, 89), (2, 3), (3, 0), (4, 5)]

like u wanted.

Another example is:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Gives the output:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Gives the output:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Gives the output:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

Hence by changing it into keys, values and items , you can print like what u wanted.Hope this helps!


m
m3.b

A simple way I found to sort a dictionary is to create a new one, based on the sorted key:value items of the one you're trying to sort. If you want to sort dict = {}, retrieve all its items using the associated method, sort them using the sorted() function then create the new dictionary.

Here's the code using dictionary comprehension :

sorted_dict = {k:v for k,v in sorted(dict.items())}

j
jax

Will generate exactly what you want:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

But this is not the correct way to do this, because, It could show a distinct behavior with different dictionaries, which I have learned recently. Hence perfect way has been suggested by Tim In the response of my Query which I am sharing here.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))

What does "show a distinct behavior with different dictionaries" mean? What is the "distinct behavior" that sorted cannot handle?
M
Mehdi Abbassi

Here is the performance of the suggested solutions:

from collections import OrderedDict
from sortedcontainers import SortedDict
import json

keys = np.random.rand(100000)
vals = np.random.rand(100000)

d = dict(zip(keys, vals))

timeit SortedDict(d)
#45.8 ms ± 780 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

timeit sorted(d.items())
#91.9 ms ± 707 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

timeit OrderedDict(sorted(d.items(), key=lambda x: x[0]))
#93.7 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

timeit dict(sorted(dic.items()))
#113 ms ± 824 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

timeit OrderedDict(sorted(dic.items()))
#122 ms ± 2.65 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

timeit json.dumps(d, sort_keys=True)
#259 ms ± 9.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

As we see, Grant Jenks's solution is by far the fastest.


l
lallolu

I think the easiest thing is to sort the dict by key and save the sorted key:value pair in a new dict.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

To make it clearer:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value

Y
Yash Shah

I come up with single line dict sorting.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

Hope this will be helpful.


R
Ramashish Baranwal

Python dicts are un-ordered. Usually, this is not a problem since the most common use case is to do a lookup.

The simplest way to do what you want would be to create a collections.OrderedDict inserting the elements in sorted order.

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

If you need to iterated, as others above have suggested, the simplest way would be to iterate over sorted keys. Examples-

Print values sorted by keys:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Get list of values sorted by keys:

values = [d[k] for k in sorted(d.keys())]

for k,value in sorted(d.items()): is better: avoids accessing the dict by key again in the loop
B
Booboo

This function will sort any dictionary recursively by its key. That is, if any value in the dictionary is also a dictionary, it too will be sorted by its key. If you are running on CPython 3.6 or greater, than a simple change to use a dict rather than an OrderedDict can be made.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)

H
Hafiz Muhammad Shafiq

Simplest solution is that you should get a list of dict key is sorted order and then iterate over dict. For example

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

Following will be the output (desending order)

e 30
b 13
d 4
c 2
a 1

P
PeterB

For the way how question is formulated, the most answers here are answering it correctly.

However, considering how the things should be really done, taking to acount decades and decades of computer science, it comes to my total suprise that there is actually only one answer here (from GrantJ user) suggesting usage of sorted associative containers (sortedcontainers) which sorts elements based on key at their insertions point.

That will avoid massive performance impact per each calling of sort(...) (at minimum O(N*log(N)), where N is in number of elements (logically, this applies for all such solutions here which suggest to use the sort(...)). Take to account that for all such solutions, the sort(...) will need to be called every time when colletion needs to be accessed as sorted AFTER it was modified by adding/removing elements ...


S
Saeid

Guys you are making things complicated ... it's really simple

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

The output is:

{'A':2,'B':1,'C':3}

Upvoted because I didn't know pprint sorts dictionaries to display them, but the OP has really asked about "going" from unsorted to sorted dict, ie OP seems to want something that remains sorted in memory, perhaps for some algorithm that requires sorted keys
This method will not allow chained assignment as pprint returns none. >>> adict = {'B':1,'A':2,'C':3} >>> ppdict = pprint(adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type() Traceback (most recent call last): File "", line 1, in AttributeError: 'NoneType' object has no attribute 'type'
M
Mohammad Mahjoub
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)

M
Mahdi Ghelichi
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}

J
Jesuisme

A timing comparison of the two methods in 2.7 shows them to be virtually identical:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 

C
Community

Or use pandas,

Demo:

>>> d={'B':1,'A':2,'C':3}
>>> df=pd.DataFrame(d,index=[0]).sort_index(axis=1)
   A  B  C
0  2  1  3
>>> df.to_dict('int')[0]
{'A': 2, 'B': 1, 'C': 3}
>>> 

See:

Docs of this Documentation of whole pandas


u
user7070507
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)

There are 14 other answers. Can you explain your code a bit and why it might be better than the other solutions?
Downvoted - Pretty unreadable code with short meaningless variable names l, l2, l3. Seems to be an attempt at an indirect and inefficient algorithm with no knowledge of python standard functions, and in any case does not work when tested on small example in original post.