ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: "To sort a dictionary"
Submitter: Alex Martelli (other recipes)
Last Updated: 2001/04/08
Version no: 1.1
Category: Searching

 

4 stars 7 vote(s)


Approved

Description:

Dictionaries can't be sorted -- a mapping has no ordering! -- so, when you feel the need to sort one, you no doubt want to sort its *keys* (in a separate list). Sorting (key,value) pairs (items) is simplest, but not fastest.

Source: Text Source

# (IMHO) the simplest approach:
def sortedDictValues1(adict):
    items = adict.items()
    items.sort()
    return [value for key, value in items]

# an alternative implementation, which
# happens to run a bit faster for large
# dictionaries on my machine:
def sortedDictValues2(adict):
    keys = adict.keys()
    keys.sort()
    return [dict[key] for key in keys]

# a further slight speed-up on my box
# is to map a bound-method:
def sortedDictValues3(adict):
    keys = adict.keys()
    keys.sort()
    return map(adict.get, keys)

Discussion:

The concept of 'sort' applies only to a collection which has _order_ -- a sequence; a mapping (e.g. a dictionary) has NO order, thus it cannot be sorted. Still, its keys can be extracted as a list, which can then be sorted. The example functions return the *values in order of sorted key*, which just happens to be the single most frequent actual need corresponding to user questions such as "how do I sort a dictionary":-)

The implementation choices are interesting. Since we are sorting key-value pairs by the key field, then returning the list of value fields, it seems clearest (conceptually simplest) to architect the solution as in the first example: .items, .sort, then a list comprehension to pick the value fields.

However (at least on my machine) this turns out not to be fastest: extracting just the keys, sorting them, then accessing the dictionary for each key in the resulting list comprehension, as in the second example, appears to be speedier.

Furthermore, it is subject to a further, obvious optimization: from the dictionary we can extract just once the bound-method adict.get, which will map each key to the corresponding value, then use builtin function map to build the list obtained by applying this callable to each item in the sorted list of keys. This does indeed provide a further speed-up (again, on my machine).

Simplicity is a great virtue, but the second and third examples aren't really more complicated (or complex) than the first -- just, perhaps, a little bit subtler. They're probably worth using to 'sort' any dictionary, even though their performance advantages are really only measurable for large ones -- because uniformity of idiom is also an important programming virtue!



Add comment

Number of comments: 12

re: dictionary 'sort', Not specified Not specified, 2002/03/26
hello,
How would you sort a dictionary if the keys are not numbers or strings but tuples
e.g. {(0, 1): 2, (0, 2): 3, ...}
- JJH
Add comment

Sorting a list of tuples/lists..., FMHj ., 2002/07/12
Where Alist = [(3, 4), (2, 3), (1, 2)], Alist.sort() yields [(1, 2), (2, 3), (3, 4)]. I love this language!
Add comment

Sorting dictionary by values, Daniel Schult, 2004/01/23
Here's some code to sort the keys of a dictionary by their associated values.


d={1:1,2:2,5:1,10:2,44:3,67:2}
items=d.items()
backitems=[ [v[1],v[0]] for v in items]
backitems.sort()
sortedlist=[ backitems[i][1] for i in range(0,len(backitems))]

Or as a function:

def sort_by_value(d):
    """ Returns the keys of dictionary d sorted by their values """
    items=d.items()
    backitems=[ [v[1],v[0]] for v in items]
    backitems.sort()
    return [ backitems[i][1] for i in range(0,len(backitems))]

Add comment

newbie sort, Muhammad Ali, 2004/10/15
I just came here straight from diveintopython section on dictionaries... Is this any different or simmilar to which solution?


def dictSort(d):
    """ returns a dictionary sorted by keys """
    our_list = d.items()
    our_list.sort()
    k = {}   
    for item in our_list:
        k[item[0]] = item[1]
    return k

Add comment

Oh my, Travis Cline, 2006/06/13
It's clear you just came over. This will not produce expected results. Read the top of this page. Dictionaries do not hold ordering information!
Add comment

typo, Nikos Kouremenos, 2005/06/06
def sortedDictValues2(adict): keys = adict.keys() keys.sort() return [*a*dict[key] for key in keys]
Add comment

List comprehensions and the 2.4 sorted() function, Frank P Mora, 2005/09/15

The 2.4 new sorted() function is grand, especially in list abstractions.

>>> di= dict(zip("e d c b a".split(),"egbdf dec cdr both any".split()))
>>> di.keys()
['a', 'c', 'b', 'e', 'd']
>>> di.items()
[('a', 'any'), ('c', 'cdr'), ('b', 'both'), ('e', 'egbdf'), ('d', 'dec')]

## sort by key
>>> [ (k,di[k]) for k in sorted(di.keys())]	## (k,v) tuples in resulting list
[('a', 'any'), ('b', 'both'), ('c', 'cdr'), ('d', 'dec'), ('e', 'egbdf')]

>>> [ di[k] for k in sorted(di.keys())]		## values only in resulting list
['any', 'both', 'cdr', 'dec', 'egbdf']

## sort by value (there is no elegant way to get the key from the value)
>>> [ k for k in sorted(di.values())]		## values (sorted) only in result
['any', 'both', 'cdr', 'dec', 'egbdf']

Add comment

sort_dict, sasa sasa, 2005/11/15
This would sort the dictionary by the field (numeric column) you supply and return the result in form of a list. def sort_dict(dictionary, field): tmp_list = [] for key, value in dictionary.items(): tmp_list.append([key, value]) tmp_list.sort(key=lambda x:x[field]) return tmp_list
Add comment

why not pass in a function to sort ???????, pepe ke, 2006/05/24
strange people, making fast things slow, easy things hard

sorting by value ...
>>> def sortfunc(x,y):
...         return cmp(x[1],y[1])
...
>>> lijst={'een':1,'drie':3,'vier':4,'twee':2}
>>> items=lijst.items()
>>> items
[('drie', 3), ('vier', 4), ('een', 1), ('twee', 2)]
>>> items.sort(sortfunc)
>>> items
[('een', 1), ('twee', 2), ('drie', 3), ('vier', 4)]
>>> items.sort()
>>> items
[('drie', 3), ('een', 1), ('twee', 2), ('vier', 4)]
>>>
of course reverse sorting would be
>>> def sortfunc(x,y):
...          return cmp(y[1],x[1])
...
>>> items.sort(sortfunc)
>>> items
[('vier', 4), ('drie', 3), ('twee', 2), ('een', 1)]
>>>
or without the need for an extra list
>>> sorted(lijst.items(),sortfunc)
[('vier', 4), ('drie', 3), ('twee', 2), ('een', 1)]
>>>

Add comment

or use a lambda expression, Aylwyn Scally, 2006/05/25
sorting dictionary d by value:
> sorted(d.items(), lambda x, y: cmp(x[1], y[1]))
and reverse sorting:
> sorted(d.items(), lambda x, y: cmp(x[1], y[1]))
Add comment

oops I meant.., Aylwyn Scally, 2006/05/25
reverse sorting:
> sorted(d.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)
Add comment

Using the new key= parameter, Alec Flett, 2006/08/25
With python 2.4 you have the key= parameter, so you can say:

sorted(d.items(), key=lambda (k,v): (v,k))
key returns the "sort key" that sort will do the comparison on.
Add comment



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. Treat the Win32 Registry ...

4. Watching a directory ...

5. Union Find data structure

6. Function Decorators by ...

7. MS SQL Server log monitor

8. Table objects with ...

9. wx twisted support using ...

10. More accurate sum




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.