How do I sort a dictionary by value?
Asked Answered
B

34

3413

I have a dictionary of values read from two fields in a database: a string field and a numeric field. The string field is unique, so that is the key of the dictionary.

I can sort on the keys, but how can I sort based on the values?

Note: I have read Stack Overflow question here How do I sort a list of dictionaries by a value of the dictionary? and probably could change my code to have a list of dictionaries, but since I do not really need a list of dictionaries I wanted to know if there is a simpler solution to sort either in ascending or descending order.

Bye answered 5/3, 2009 at 0:49 Comment(5)
The dictionary data structure does not have inherent order. You can iterate through it but there's nothing to guarantee that the iteration will follow any particular order. This is by design, so your best bet is probaly using anohter data structure for representation.Ejective
"sorted()" can operate on dictionaries (and returns a list of sorted keys), so I think he's aware of this. Without knowing his program, it's absurd to tell someone they're using the wrong data structure. If fast lookups are what you need 90% of the time, then a dict is probably what you want.Cori
All three outputs (keys, values, both) for sorting dictionaries are covered here in a clear and concise style: https://mcmap.net/q/40708/-sort-dict-by-value-python-duplicateRectitude
@Ejective The base class might not be ordered but OrderedDict is of course.Narva
In Python 3.6+ dictionaries preserve insertion order. This is, of course, not the same as possibility of sorting them by value, but on the other hand it is no longer valid to say that "dictionary data structure does not have inherent order".Renter
E
6927

Python 3.7+ or CPython 3.6

Dicts preserve insertion order in Python 3.7+. Same in CPython 3.6, but it's an implementation detail.

>>> x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> {k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

or

>>> dict(sorted(x.items(), key=lambda item: item[1]))
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

Older Python

It is not possible to sort a dictionary, only to get a representation of a dictionary that is sorted. Dictionaries are inherently orderless, but other types, such as lists and tuples, are not. So you need an ordered data type to represent sorted values, which will be a list—probably a list of tuples.

For instance,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_x will be a list of tuples sorted by the second element in each tuple. dict(sorted_x) == x.

And for those wishing to sort on keys instead of values:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

In Python3 since unpacking is not allowed we can use

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])

If you want the output as a dict, you can use collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)
Euchromatin answered 5/3, 2009 at 0:59 Comment(11)
for timings on various dictionary sorting by value schemes: writeonly.wordpress.com/2008/08/30/…Gave
sorted_x.reverse() will give you a descending ordering (by the second tuple element)Invocate
saidimu: Since we're already using sorted(), it's much more efficient to pass in the reverse=True argument.Glengarry
In python3 I used a lambda: sorted(d.items(), key=lambda x: x[1]). Will this work in python 2.x?Flapjack
in case of value have same value how to ensure value with smaller key come first?Gastrula
map = {k: v for k, v in sorted(map.items(), key=lambda item: item[1], reverse=True)} use this for reverse(descending) order.Thrall
Why this is not working now {k: v for k, v in sorted(x.items(), key=lambda item: item[1])}Airlift
Where can I read more about the usage of key=lambda item :item[1] please? The part I don't quite understand is the item[1], is it because when we do x.items() it returns the key-value pairs and with this we can tap into the value by doing item[1]?Overcast
just remind that OrderedDict cannot output the sorted dictionary by value.Trunnion
@Overcast yes, dict.keys() returns an iterable object whose elements are (key,value) tuples. Sorted passes those elements to the "key=" function/lambda to get the sort key (not to be confused with the dictionary key). So yes "lambda item :item[1]" is taking a (key,value) tuple and extracting the value.Uropygium
you can also use also a list comprehension for a dictionary. Pretty straight forward in my opinion. sorted_x = {key: value for key, value in sorted_x}Modulation
R
1614

As simple as: sorted(dict1, key=dict1.get)

Well, it is actually possible to do a "sort by dictionary values". Recently I had to do that in a Code Golf (Stack Overflow question Code golf: Word frequency chart). Abridged, the problem was of the kind: given a text, count how often each word is encountered and display a list of the top words, sorted by decreasing frequency.

If you construct a dictionary with the words as keys and the number of occurrences of each word as value, simplified here as:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
    d[w] += 1

then you can get a list of the words, ordered by frequency of use with sorted(d, key=d.get) - the sort iterates over the dictionary keys, using the number of word occurrences as a sort key .

for w in sorted(d, key=d.get, reverse=True):
    print(w, d[w])

I am writing this detailed explanation to illustrate what people often mean by "I can easily sort a dictionary by key, but how do I sort by value" - and I think the original post was trying to address such an issue. And the solution is to do sort of list of the keys, based on the values, as shown above.

Racemic answered 5/7, 2010 at 8:1 Comment(9)
This is also good but key=operator.itemgetter(1) should be more scalable for efficiency than key=d.getLeyte
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True) and for key, val in sorted_keys: print "%s: %d" % (key, val) - itemgetter creates a function when it's called, you don't use it directly like in your example. And a plain iteration on a dict uses the keys without the valuesDachshund
i have come from the future to tell you of collections.Counter, which has a most_common method that might interest you :)Girdle
@Girdle fun fact Counter was new in 3.1 which was released in 2009, so this answer was always outdated :-)Phenix
You can also use this in a dictionary comprehension: sorted_words = {key:words[key] for key in sorted(words,key=words.get)}Richelieu
@Richelieu if you want to construct a new dictionary, see it covered in answer https://mcmap.net/q/40389/-how-do-i-sort-a-dictionary-by-value above. Note dictionary order preserved only since Python 3.7+ (last 5 years)Racemic
Considering 3.7 was EOL 5 months ago, and 3.6 was EOL over 2yrs ago. I would not recommend any solution <3.7 (really <3.8) unless the ultimate goal is to open a ton of security holes in your application <3<3. But you could always just use an OrderedDict.Richelieu
@NasBanov what's the time complexity of this operation?Eudosia
@Eudosia O(sorted) 😁, i.e. whatever Python's implementation is. It's N log N but highly optimized, i believeRacemic
P
1149

You could use:

sorted(d.items(), key=lambda x: x[1])

This will sort the dictionary by the values of each entry within the dictionary from smallest to largest.

To sort it in descending order just add reverse=True:

sorted(d.items(), key=lambda x: x[1], reverse=True)

Input:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}
a = sorted(d.items(), key=lambda x: x[1])    
print(a)

Output:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
Premed answered 13/2, 2010 at 16:33 Comment(7)
From what I've seen (docs.python.org/2/library/…), there is a class called OrderedDict which can be sorted and retain order whilst still being a dictionary. From the code examples, you can use lambda to sort it, but I haven't tried it out personally :PHouchens
I'd prefer key=lambda (k, v): v personallyPlacidia
@Keyo shouldn't that be it returns an ordered list of keys (sorted by values) not (k,v) tuples? That's what I get with Python 2.7.10. @Nyxynyx add the parameter reverse=True to sort in descending order.Sanitary
@Placidia I like that (k, v) syntax too, but it's not available in Python 3 where tuple parameter unpacking was removed.Ragg
If you wrap this in an OrderedDict() instance you will get a (ordered) dict instead of list of tuples!Melyndamem
What if the dictionary has multiple values with the same value and we would want to sort the dictionary which consists of multiple same values where smaller value frequency gets printed first followed by larger value?Zumstein
This worked, and for some reason the top answers did not.Champion
G
267

Dicts can't be sorted, but you can build a sorted list from them.

A sorted list of dict values:

sorted(d.values())

A list of (key, value) pairs, sorted by value:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))
Gripe answered 5/3, 2009 at 1:5 Comment(3)
What order are keys with the same value placed in? I sorted the list by keys first, then by values, but the order of the keys with the same value does not remain.Ossification
Dicts can now be sorted, starting with CPython 3.6 and all other Python implementations starting with 3.7Colan
True at the time, but now python dictionaries preserve the order in which items were inserted already by default. And therefore they can be sorted.Glop
F
181

In recent Python 2.7, we have the new OrderedDict type, which remembers the order in which the items were added.

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

To make a new ordered dictionary from the original, sorting by the values:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

The OrderedDict behaves like a normal dict:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])
Falstaffian answered 5/7, 2010 at 2:50 Comment(7)
This is not what the question is about - it is not about maintaining order of keys but about "sorting by value"Racemic
@Nas Banov: it is NOT sorting by the key. it is sorting in the order, we create the items. in our case, we sort by the value. unfortunately, the 3-item dict was unfortunately chosen so the order was the same, when sorted voth by value and key, so i expanded the sample dict.Falstaffian
sorted(d.items(), key=lambda x: x[1]) Can you explain what the x means, why it can take x[1] to lambda? Why does it can't be x[0]? Thank you very much!Bywoods
@jie d.items() returns a list of key/value pairs from the dictionary and x is an element of this tuple. x[0] will be key and x[1] will be the value. As we intend to sort on the value, we pass x[1] to the lambda.Amadus
may be a stupid question: x: x[1] - what does the 1 access? The value itself? What is 0 then? The key?Granthem
@Granthem d.items() returns a list-like container of (key, value) tuples. [0] accesses the first element of the tuple -- the key -- and [1] accesses the second element -- the value.Morgen
Note: As of 3.6 (as a CPython/PyPy implementation detail) and as of 3.7 (as a Python language guarantee), plain dict is insertion ordered as well, so you can just replace OrderedDict with dict for code running on modern Python. OrderedDict isn't really needed anymore unless you need to rearrange the order of an existing dict (with move_to_end/popitem) or need equality comparisons to be order-sensitive. It uses a lot more memory than plain dict, so if you can, dict is the way to go.Whimsey
F
125

Using Python 3.5

Whilst I found the accepted answer useful, I was also surprised that it hasn't been updated to reference OrderedDict from the standard library collections module as a viable, modern alternative - designed to solve exactly this type of problem.

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

The official OrderedDict documentation offers a very similar example too, but using a lambda for the sort function:

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

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
Fredericksburg answered 5/12, 2015 at 9:46 Comment(1)
can you explain what itemgetter does in this example? otherwise this seems just as cryptic as using a lambaGlop
O
116

Pretty much the same as Hank Gay's answer:

sorted([(value,key) for (key,value) in mydict.items()])

Or optimized slightly as suggested by John Fouhy:

sorted((value,key) for (key,value) in mydict.items())
Owl answered 5/3, 2009 at 1:6 Comment(4)
..and as with Hank Gay's answer, you don't need the square brackets. sorted() will happily take any iterable, such as a generator expression.Ameeameer
You may still need to swap the (value,key) tuple elements to end up with the (key, value). Another list comprehension is then needed. [(key, value) for (value, key) in sorted_list_of_tuples]Invocate
no, it's better to leave square brackets, because sorted will have to rebuild the list anyway, and rebuilding from gencomp will be faster. Good for codegolfing, bad for speed. Keep the ugly ([]) version.Fetial
I'm confused, this returns an array of tuples not a dict. IMO you are missing the dict comprehension part: {x: v for x, v in sorted((value, key) for (key, value) in mydict.items())}Hooker
A
87

As of Python 3.6 the built-in dict will be ordered

Good news, so the OP's original use case of mapping pairs retrieved from a database with unique string ids as keys and numeric values as values into a built-in Python v3.6+ dict, should now respect the insert order.

If say the resulting two column table expressions from a database query like:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

would be stored in two Python tuples, k_seq and v_seq (aligned by numerical index and with the same length of course), then:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

Allow to output later as:

for k, v in ordered_map.items():
    print(k, v)

yielding in this case (for the new Python 3.6+ built-in dict!):

foo 0
bar 1
baz 42

in the same ordering per value of v.

Where in the Python 3.5 install on my machine it currently yields:

bar 1
foo 0
baz 42

Details:

As proposed in 2012 by Raymond Hettinger (cf. mail on python-dev with subject "More compact dictionaries with faster iteration") and now (in 2016) announced in a mail by Victor Stinner to python-dev with subject "Python 3.6 dict becomes compact and gets a private version; and keywords become ordered" due to the fix/implementation of issue 27350 "Compact and ordered dict" in Python 3.6 we will now be able, to use a built-in dict to maintain insert order!!

Hopefully this will lead to a thin layer OrderedDict implementation as a first step. As @JimFasarakis-Hilliard indicated, some see use cases for the OrderedDict type also in the future. I think the Python community at large will carefully inspect, if this will stand the test of time, and what the next steps will be.

Time to rethink our coding habits to not miss the possibilities opened by stable ordering of:

  • Keyword arguments and
  • (intermediate) dict storage

The first because it eases dispatch in the implementation of functions and methods in some cases.

The second as it encourages to more easily use dicts as intermediate storage in processing pipelines.

Raymond Hettinger kindly provided documentation explaining "The Tech Behind Python 3.6 Dictionaries" - from his San Francisco Python Meetup Group presentation 2016-DEC-08.

And maybe quite some Stack Overflow high decorated question and answer pages will receive variants of this information and many high quality answers will require a per version update too.

Caveat Emptor (but also see below update 2017-12-15):

As @ajcr rightfully notes: "The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon." (from the whatsnew36) not nit picking, but the citation was cut a bit pessimistic ;-). It continues as " (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)."

So as in some human languages (e.g. German), usage shapes the language, and the will now has been declared ... in whatsnew36.

Update 2017-12-15:

In a mail to the python-dev list, Guido van Rossum declared:

Make it so. "Dict keeps insertion order" is the ruling. Thanks!

So, the version 3.6 CPython side-effect of dict insertion ordering is now becoming part of the language spec (and not anymore only an implementation detail). That mail thread also surfaced some distinguishing design goals for collections.OrderedDict as reminded by Raymond Hettinger during discussion.

Anthesis answered 10/9, 2016 at 10:5 Comment(3)
@ajcr thanks for the caveat, very appreciated - as smileys and maybe's were weaved into my response,these should indicated, the change is massive but of course, only available for CPython (reference implementation) and PyPy. For something completely different ... I rarely talk to non-implementation details when coding man-machine instructions. If it would only have been Jython ;-) ... I might not have had the courage to write it.Anthesis
OrderedDict definitely won't be dropped; instead, it will become a thin wrapper around the current dict implementation (so you might add that it will become more compact, too). Adding that snippet with the ImportError isn't quite the best idea due to it misleading readers that OrderedDict has no use.Alcohol
In a response to this answer, and structured dicts, I posted a new answer. Feedback welcome!Dominions
H
84

It can often be very handy to use namedtuple. For example, you have a dictionary of 'name' as keys and 'score' as values and you want to sort on 'score':

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

sorting with lowest score first:

worst = sorted(Player(v,k) for (k,v) in d.items())

sorting with highest score first:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

Now you can get the name and score of, let's say the second-best player (index=1) very Pythonically like this:

player = best[1]
player.name
    'Richard'
player.score
    7
Hepta answered 30/8, 2011 at 0:30 Comment(2)
How could I convert it back to a dictionary?Fagoting
as_list=[Player(v,k) for (k,v) in d.items()] as_dict=dict((p.name,p.score) for p in as_list)Hepta
R
63

Starting from Python 3.6, dict objects are now ordered by insertion order. It's officially in the specifications of Python 3.7.

>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

Before that, you had to use OrderedDict.

Python 3.7 documentation says:

Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was implementation detail of CPython from 3.6.

Rivarivage answered 15/9, 2018 at 13:37 Comment(2)
works great! dict(sorted(words.items(), key=lambda x: x[1], reverse=True)) for DESCOration
Also this works : {key:words[key] for key in sorted(words,key=words.get)} (add reverse=True for DESC)Richelieu
E
54

I had the same problem, and I solved it like this:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(People who answer "It is not possible to sort a dict" did not read the question! In fact, "I can sort on the keys, but how can I sort based on the values?" clearly means that he wants a list of the keys sorted according to the value of their values.)

Please notice that the order is not well defined (keys with the same value will be in an arbitrary order in the output list).

Extemporaneous answered 18/11, 2010 at 14:19 Comment(2)
Note that you're both iterating the dictionary and fetching values by their key, so performance wise this is not an optimal solution.Uredium
@Dejell: as the contributor says, he interprets the question as "can I get the list of keys sorted according to the values". We don't need the values in the result, we have them in the dictionary.Palmar
R
52

If values are numeric you may also use Counter from collections.

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    
Revetment answered 27/6, 2012 at 15:43 Comment(2)
what about if you dictionary is >>> x={'hello':1,'python':5, 'world':300}Dorman
@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common() gives [('world', 300), ('python', 5), ('hello', 1)]. This actually works for any sortable value type (although many other Counter operations do require values to be comparable to ints).Duchess
H
42

In Python 2.7, simply do:

from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
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)])

copy-paste from : http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Enjoy ;-)

Haemachrome answered 22/8, 2013 at 8:38 Comment(0)
D
32

This is the code:

import operator
origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

Here are the results:

Original

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

Rank

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
Decontaminate answered 8/3, 2011 at 2:6 Comment(0)
M
32

Try the following approach. Let us define a dictionary called mydict with the following data:

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

If one wanted to sort the dictionary by keys, one could do something like:

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

This should return the following output:

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

On the other hand, if one wanted to sort a dictionary by value (as is asked in the question), one could do the following:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

The result of this command (sorting the dictionary by value) should return the following:

bob: 1
alan: 2
danny: 3
carl: 40
Manipur answered 7/4, 2014 at 4:46 Comment(2)
Awesome! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]): allows you to sort by a subkeyFining
this doesn't work in later versions of python that dont support tuple unpacking and where dicts no longer have iteritems()Klarrisa
S
28

You can create an "inverted index", also

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

Now your inverse has the values; each value has a list of applicable keys.

for k in sorted(inverse):
    print k, inverse[k]
Sublittoral answered 5/3, 2009 at 1:52 Comment(0)
L
27

You can use the collections.Counter. Note, this will work for both numeric and non-numeric values.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])
Lakh answered 9/3, 2013 at 12:30 Comment(1)
How is this different from Ivan Sas's answer?Nutlet
C
25

The collections solution mentioned in another answer is absolutely superb, because you retain a connection between the key and value which in the case of dictionaries is extremely important.

I don't agree with the number one choice presented in another answer, because it throws away the keys.

I used the solution mentioned above (code shown below) and retained access to both keys and values and in my case the ordering was on the values, but the importance was the ordering of the keys after ordering the values.

from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print( c.most_common() )


>> [('python', 5), ('world', 3), ('hello', 1)]
Consonance answered 3/3, 2014 at 14:58 Comment(0)
I
21

You can also use a custom function that can be passed to parameter key.

def dict_val(x):
    return x[1]

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)
Intravasation answered 25/5, 2017 at 18:13 Comment(2)
This is the only answer that worked so far in python 2.7Heflin
End-of-life for Python 2 was in 2020.Nutlet
P
19

You can use a skip dict which is a dictionary that's permanently sorted by value.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

If you use keys(), values() or items() then you'll iterate in sorted order by value.

It's implemented using the skip list datastructure.

Portillo answered 25/9, 2014 at 22:56 Comment(2)
can we change the order of sort, right now, it is asending, but I want decsending.Manful
afaik you would have to negate your values in order to reverse the orderingPortillo
T
17

Of course, remember, you need to use OrderedDict because regular Python dictionaries don't keep the original order.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))

If you do not have Python 2.7 or higher, the best you can do is iterate over the values in a generator function. (There is an OrderedDict for 2.4 and 2.6 here, but

a) I don't know about how well it works

and

b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)


def gen(originalDict):
    for x, y in sorted(zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

You can also print out every value

for bleh, meh in gen(myDict):
    print(bleh, meh)

Please remember to remove the parentheses after print if not using Python 3.0 or above

Toplofty answered 31/7, 2015 at 8:8 Comment(1)
regular Python dictionaries don't keep the original order — as of Python 3.7, they do.Crissie
I
16

I just learned a relevant skill from Python for Everybody.

You may use a temporary list to help you to sort the dictionary:

# Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# Create a temporary list
tmp = []

# Iterate through the dictionary and append each tuple into the temporary list
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# Sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

If you want to sort the list in descending order, simply change the original sorting line to:

tmp = sorted(tmp, reverse=True)

Using list comprehension, the one-liner would be:

# Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
# One-liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
# One-liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

Sample Output:

# Ascending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
# Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]
Incalculable answered 27/5, 2018 at 17:45 Comment(1)
If you want to print it in the initial format you should do:print ([(k,v) for v,k in sorted([(v,k) for k,v in d.items()])]) . The output is: [('orange', 1.0), ('apple', 500.1), ('pineapple', 789.0), ('banana', 1500.2)]. With [(k,v) for v,k in sorted([(v,k) for k,v in d.items()], reverse = True)] the output is: [('banana', 1500.2), ('pineapple', 789.0), ('apple', 500.1), ('orange', 1.0)]Incognizant
E
15
from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict
Ep answered 1/11, 2010 at 12:16 Comment(1)
question was: sort by value, not by keys... I like seeing a function. You can import collections and of course use sorted(data.values())Hepta
I
15

Here is a solution using zip on d.values() and d.keys(). A few lines down this link (on Dictionary view objects) is:

This allows the creation of (value, key) pairs using zip(): pairs = zip(d.values(), d.keys()).

So we can do the following:

d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(zip(d.values(), d.keys()))

print d_sorted 
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]
Indemnify answered 20/6, 2015 at 1:44 Comment(0)
D
14

As pointed out by Dilettant, Python 3.6 will now keep the order! I thought I'd share a function I wrote that eases the sorting of an iterable (tuple, list, dict). In the latter case, you can sort either on keys or values, and it can take numeric comparison into account. Only for >= 3.6!

When you try using sorted on an iterable that holds e.g. strings as well as ints, sorted() will fail. Of course you can force string comparison with str(). However, in some cases you want to do actual numeric comparison where 12 is smaller than 20 (which is not the case in string comparison). So I came up with the following. When you want explicit numeric comparison you can use the flag num_as_num which will try to do explicit numeric sorting by trying to convert all values to floats. If that succeeds, it will do numeric sorting, otherwise it'll resort to string comparison.

Comments for improvement welcome.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))
      
      return _sorted
      
    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")
Dominions answered 2/3, 2018 at 16:48 Comment(0)
J
10

Use ValueSortedDict from dicts:

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
Jeweller answered 19/10, 2011 at 6:25 Comment(0)
A
10

Iterate through a dict and sort it by its values in descending order:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1
Autopilot answered 30/10, 2011 at 19:42 Comment(0)
I
9

If your values are integers, and you use Python 2.7 or newer, you can use collections.Counter instead of dict. The most_common method will give you all items, sorted by the value.

Immanuel answered 24/1, 2012 at 19:28 Comment(0)
A
8

This works in 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)
Accessible answered 16/11, 2011 at 7:32 Comment(0)
L
8

For the sake of completeness, I am posting a solution using heapq. Note, this method will work for both numeric and non-numeric values

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
Lakh answered 23/3, 2013 at 14:19 Comment(0)
T
6
months = {"January": 31, "February": 28, "March": 31, "April": 30, "May": 31,
          "June": 30, "July": 31, "August": 31, "September": 30, "October": 31,
          "November": 30, "December": 31}

def mykey(t):
    """ Customize your sorting logic using this function.  The parameter to
    this function is a tuple.  Comment/uncomment the return statements to test
    different logics.
    """
    return t[1]              # sort by number of days in the month
    #return t[1], t[0]       # sort by number of days, then by month name
    #return len(t[0])        # sort by length of month name
    #return t[0][-1]         # sort by last character of month name


# Since a dictionary can't be sorted by value, what you can do is to convert
# it into a list of tuples with tuple length 2.
# You can then do custom sorts by passing your own function to sorted().
months_as_list = sorted(months.items(), key=mykey, reverse=False)

for month in months_as_list:
    print month
Tarboosh answered 13/2, 2014 at 23:18 Comment(0)
D
1

Besides using built-in modules, etc., I try solve it manually...

First, I made a function whose job is to returning minimal value each items of the dict:

def returnminDict(_dct):
    dict_items = _dct.items()
    list_items = list(dict_items)
    init_items = list_items[0]
    for i in range(len(list_items)):
        if list_items[i][1] > init_items[1]:
           continue
        else:
           init_items = list_items[i]
    return init_items

Second, now we have a function which returns an item that has the minimal value. Then I make a new dict and loop over the dict:

def SelectDictSort(_dct):
    new_dict = {}
    while _dct:
        mindict = returnminDict(_dct)
        new_dict.update(dict((mindict,)))
        _dct.pop(mindict[0])
    return new_dict

I try with SelectDictSort({2: 5, 5: 1, 4: 3, 1: 1, 0: 1, 9: 2, 8: 2}). It will return:

{0: 1, 1: 1, 5: 1, 8: 2, 9: 2, 4: 3, 2: 5}

Hmmm... I don’t know which is correct, but this what I have tried...

Dynamometer answered 26/2, 2019 at 4:12 Comment(0)
C
0

Using Python 3.2:

x = {"b":4, "a":3, "c":1}
for i in sorted(x.values()):
    print(list(x.keys())[list(x.values()).index(i)])
Cartage answered 3/11, 2012 at 11:7 Comment(0)
S
-2

This method will not use lambda and works well on Python 3.6:

 # sort dictionary by value
d = {'a1': 'fsdfds', 'g5': 'aa3432ff', 'ca':'zz23432'}
def getkeybyvalue(d,i):
    for k, v in d.items():
        if v == i:
            return (k)

sortvaluelist = sorted(d.values())

# In >> Python 3.6+ << the INSERTION-ORDER of a dict is preserved. That is,
# when creating a NEW dictionary and filling it 'in sorted order',
# that order will be maintained.
sortresult ={}
for i1 in sortvaluelist:   
    key = getkeybyvalue(d,i1)
    sortresult[key] = i1
print ('=====sort by value=====')
print (sortresult)
print ('=======================')
Schematize answered 24/5, 2017 at 3:19 Comment(2)
From review queue: May I request you to please add some context around your source-code. Code-only answers are difficult to understand. It will help the asker and future readers both if you can add more information in your post.Pustule
this is a very inefficient solution, with linear search and allFetial

© 2022 - 2024 — McMap. All rights reserved.