views:

12847

answers:

9

I have a dictionary of values read from 2 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 this post 72899 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 a simpler solution.

+1  A: 

Technically, dictionaries aren't sequences, and therefore can't be sorted. You can do something like

sorted(a_dictionary.values())

assuming performance isn't a huge deal.

UPDATE: Thanks to the commenters for pointing out that I made this way too complicated in the beginning.

Hank Gay
The list comprehension is no longer needed. You can simply pass in sorted(a_dictionary.values()). Even faster, if we want more would be to do foo = a_dictionary.values(); foo.sort() . I don't think speed is that much of an issue, though. Getting rid of the listcomp would simply eliminate redundancy.
Devin Jeanpierre
+42  A: 

It is not possible to sort a dict, only to get a representation of a dict that is sorted. Dicts are inherently orderless, but other types, such as lists and tuples, are not. So you need a sorted representation, 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.iteritems(), key=operator.itemgetter(1))

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

Devin Jeanpierre
for timings on various dictionary sorting by value schemes: http://writeonly.wordpress.com/2008/08/30/sorting-dictionaries-by-value-in-python-improved/
Gregg Lind
`sorted_x.reverse()` will give you a descending ordering (by the second tuple element)
saidimu
saidimu: Since we're already using `sorted()`, it's much more efficient to pass in the `reverse=True` argument.
rmh
+19  A: 

Dicts can't be sorted, but you can build 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))
Roberto Bonvallet
+6  A: 

Pretty much the same as Hank Gay's answer;

sorted([(value,key) for (key,value) in mydict.items()])
..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.
John Fouhy
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]`
saidimu
+3  A: 

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]
S.Lott
+3  A: 

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.

Mark
+2  A: 

in recent Python 2.7, we have 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}

>>> from collections import OrderedDict
>>> # make a new ordered dictionary from the original,
>>> # sorting its items by values
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

>>> # 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)])
mykhal
This is not what the question is about - it is not about maintaining order of keys but about "sorting by value"
Nas Banov
@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.
mykhal
+10  A: 

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

Well, it is actually possible to do a "sort by dictionary values". Recently had to do that in a Code Golf (http://stackoverflow.com/questions/3169051#3170549). Abridged, the problem was of the kind: given a text, count how often each word is encountered and display list of the top words, sorted by decreasing frequency.

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

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

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

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

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

Nas Banov