By masi


2008-09-16 14:27:47 8 Comments

I have a list of dictionaries and want each item to be sorted by a specific property values.

Take into consideration the array below,

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

When sorted by name, should become

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]

19 comments

@vikas0713 2019-03-11 08:11:57

You can use itemgetter ,if you want to consider the performance. itemgetter typically runs bit faster than lambda.

from operator import itemgetter
result = sorted(data, key=itemgetter('age'))  # this will sort list by property order 'age'.

@Loochie 2018-11-30 09:40:11

You may use the following code

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

@Srisaila 2017-12-19 17:31:30

If you do not need the original list of dictionaries, you could modify it in-place with sort() method using a custom key function.

Key function:

def get_name(d):
    """ Return the value of a key in a dictionary. """

    return d["name"]

The list to be sorted:

data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]

Sorting it in-place:

data_one.sort(key=get_name)

If you need the original list, call the sorted() function passing it the list and the key function, then assign the returned sorted list to a new variable:

data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
new_data = sorted(data_two, key=get_name)

Printing data_one and new_data.

>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]

@uingtea 2017-07-14 03:21:08

sometime we need to use lower() for example

lists = [{'name':'Homer', 'age':39},
  {'name':'Bart', 'age':10},
  {'name':'abby', 'age':9}]

lists = sorted(lists, key=lambda k: k['name'])
print(lists)
# [{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}, {'name':'abby', 'age':9}]

lists = sorted(lists, key=lambda k: k['name'].lower())
print(lists)
# [ {'name':'abby', 'age':9}, {'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]

@forzagreen 2017-03-17 10:29:50

a = [{'name':'Homer', 'age':39}, ...]

# This changes the list a
a.sort(key=lambda k : k['name'])

# This returns a new list (a is not modified)
sorted(a, key=lambda k : k['name']) 

@abby sobh 2016-09-01 21:21:11

Using the pandas package is another method, though it's runtime at large scale is much slower than the more traditional methods proposed by others:

import pandas as pd

listOfDicts = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
df = pd.DataFrame(listOfDicts)
df = df.sort_values('name')
sorted_listOfDicts = df.T.to_dict().values()

Here are some benchmark values for a tiny list and a large (100k+) list of dicts:

setup_large = "listOfDicts = [];\
[listOfDicts.extend(({'name':'Homer', 'age':39}, {'name':'Bart', 'age':10})) for _ in range(50000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(listOfDicts);"

setup_small = "listOfDicts = [];\
listOfDicts.extend(({'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(listOfDicts);"

method1 = "newlist = sorted(listOfDicts, key=lambda k: k['name'])"
method2 = "newlist = sorted(listOfDicts, key=itemgetter('name')) "
method3 = "df = df.sort_values('name');\
sorted_listOfDicts = df.T.to_dict().values()"

import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method LC2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))

t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method LC2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup_large)
print('Large Method Pandas: ' + str(t.timeit(1)))

#Small Method LC: 0.000163078308105
#Small Method LC2: 0.000134944915771
#Small Method Pandas: 0.0712950229645
#Large Method LC: 0.0321750640869
#Large Method LC2: 0.0206089019775
#Large Method Pandas: 5.81405615807

@clp2 2016-11-07 04:05:26

I ran your code and found a mistake in the the timeit.Timer args for Large Method Pandas: you specify "setup_small" where it should be "setup_large". Changing that arg caused the program to run without finishing, and I stopped it after more than 5 minutes. When I ran it with "timeit(1)", the Large Method Pandas finished in 7.3 sec, much worse than LC or LC2.

@abby sobh 2016-11-08 22:58:51

You're quite right, that was quite an oversight on my part. I no longer recommend it for large cases! I have edited the answer to simply allow it as a possibility, the use case is still up for debate.

@pjz 2008-09-16 14:39:11

my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

my_list.sort(lambda x,y : cmp(x['name'], y['name']))

my_list will now be what you want.

(3 years later) Edited to add:

The new key argument is more efficient and neater. A better answer now looks like:

my_list = sorted(my_list, key=lambda k: k['name'])

...the lambda is, IMO, easier to understand than operator.itemgetter, but YMMV.

@vvladymyrov 2015-01-22 17:21:17

Here is the alternative general solution - it sorts elements of dict by keys and values. The advantage of it - no need to specify keys, and it would still work if some keys are missing in some of dictionaries.

def sort_key_func(item):
    """ helper function used to sort list of dicts

    :param item: dict
    :return: sorted list of tuples (k, v)
    """
    pairs = []
    for k, v in item.items():
        pairs.append((k, v))
    return sorted(pairs)
sorted(A, key=sort_key_func)

@Mario F 2008-09-16 14:39:44

It may look cleaner using a key instead a cmp:

newlist = sorted(list_to_be_sorted, key=lambda k: k['name']) 

or as J.F.Sebastian and others suggested,

from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name')) 

For completeness (as pointed out in comments by fitzgeraldsteele), add reverse=True to sort descending

newlist = sorted(l, key=itemgetter('name'), reverse=True)

@jfs 2008-09-16 15:03:43

Using key is not only cleaner but more effecient too.

@jfs 2008-09-16 15:05:27

lambda k: k['name'] could be replaced by operator.itemgetter('name').

@NealWalters 2009-10-13 04:14:16

What would you change to make it sort descending?

@Mario F 2009-10-13 07:14:38

The fastest way would be to add a newlist.reverse() statement. Otherwise you can define a comparison like cmp=lambda x,y: - cmp(x['name'],y['name']).

@Philluminati 2009-11-20 15:16:18

if the sort value is a number you could say: lambda k: (k['age'] * -1) to get a reverse sort

@fitzgeraldsteele 2009-11-24 21:57:30

To sort descending: newlist = sorted(l, key=itemgetter('name'), reverse=True)

@radicand 2012-07-11 23:14:38

This also applies to a list of tuples, if you use itemgetter(i) where i is the index of the tuple element to sort on.

@Bakuriu 2012-09-07 17:59:06

itemgetter accepts more than one argument: itemgetter(1,2,3) is a function that return a tuple like obj[1], obj[2], obj[3], so you can use it to do complex sorts.

@olovholm 2013-09-12 20:20:29

How could this be done if my dictionaries did not have a set key, but instead being structured more like a hashmap with the key being unique for each element. Is there a way of makeing lambda or itemgetter sorting on the value of the dictionary element wrapped inside the list?

@Akash Kothawale 2014-06-19 17:33:10

With do I do if I want to sort based on values of multiple keys? (This is basically the situation where some of the elements of the first key are same and I need the item to be sorted based on the following key)

@Stefan Gruenwald 2014-11-03 20:06:03

sort reverse with key: print sorted(newlist,key=lambda k: k['name'],reverse=True)

@Bruno Bronosky 2016-05-18 19:54:16

As @radicand mentioned, you can use this info for lists of tuples, lists, or complex objects. The non-itemgetter version is newlist = sorted(list_to_be_sorted, key=lambda k: k[index]) or newlist = sorted(list_to_be_sorted, key=lambda k: k[index_integer]['subkey'][subindex_integer])

@user1063287 2016-07-27 15:24:54

Using my_list = [{"id":"1", "text":"Able"},{"id":"2", "text":"app-time"},{"id":"3", "text":"Red"}] in the above solutions, Red is placed before app-time. Is there anyway to ensure alphabetical sorting with hyphenated words?

@Kanchan Srivastava 2017-10-13 07:37:33

If value for the corresponding key is None, it will throw exception TypeError: '<' not supported between instances of 'str' and 'NoneType'. How will you fix that with this solution?

@Carlos Andres 2018-10-12 18:43:01

You're the best dude :)

@simkus 2019-01-08 03:51:55

Thanks, it's best for the job to do!

@AdelaN 2019-02-26 11:01:30

@KanchanSrivastava, you can't really do anything about it with itemgetter, but for the other solution, it would be something like: newlist = sorted(list_to_be_sorted, key=lambda k: k['name'] or '')

@Shank_Transformer 2014-04-16 07:18:21

Lets Say I h'v a Dictionary D with elements below. To sort just use key argument in sorted to pass custom function as below

D = {'eggs': 3, 'ham': 1, 'spam': 2}

def get_count(tuple):
    return tuple[1]

sorted(D.items(), key = get_count, reverse=True)
or
sorted(D.items(), key = lambda x: x[1], reverse=True)  avoiding get_count function call

https://wiki.python.org/moin/HowTo/Sorting/#Key_Functions

@octoback 2013-05-27 11:21:03

Using Schwartzian transform from Perl,

py = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

do

sort_on = "name"
decorated = [(dict_[sort_on], dict_) for dict_ in py]
decorated.sort()
result = [dict_ for (key, dict_) in decorated]

gives

>>> result
[{'age': 10, 'name': 'Bart'}, {'age': 39, 'name': 'Homer'}]

More on Perl Schwartzian transform

In computer science, the Schwartzian transform is a Perl programming idiom used to improve the efficiency of sorting a list of items. This idiom is appropriate for comparison-based sorting when the ordering is actually based on the ordering of a certain property (the key) of the elements, where computing that property is an intensive operation that should be performed a minimal number of times. The Schwartzian Transform is notable in that it does not use named temporary arrays.

@Antti Haapala 2015-02-15 20:11:29

Python has supported the key= for .sort since 2.4, that is year 2004, it does the Schwartzian transform within the sorting code, in C; thus this method is useful only on Pythons 2.0-2.3. all of which are more than 12 years old.

@vemury 2008-09-16 15:18:14

import operator

To sort the list of dictionaries by key='name':

list_of_dicts.sort(key=operator.itemgetter('name'))

To sort the list of dictionaries by key='age':

list_of_dicts.sort(key=operator.itemgetter('age'))

@monojohnny 2010-02-17 13:10:57

Anyway to combine name and age ? (like in SQL ORDER BY name,age ?)

@njzk2 2013-05-29 13:29:17

what is the advantage of itemgetter over lambda ?

@Claudiu 2013-09-04 22:21:15

@monojohnny: yes, just have the key return a tuple, key=lambda k: (k['name'], k['age']). (or key=itemgetter('name', 'age')). tuple's cmp will compare each element in turn. it's bloody brilliant.

@TTT 2014-02-21 15:21:55

In the documentation (docs.python.org/2/tutorial/datastructures.html) the optional key argument for list.sort() is not described. Any idea where to find that?

@IceArdor 2014-09-05 01:23:48

@monojohnny sorted(list_of_dicts, key=operator.itemgetter('name','age')) sorts the list of dictionaries by the name key then the age key.

@Kevin 2015-02-19 14:56:53

@TTT: See the library documentation for list and friends.

@Dologan 2010-05-18 15:28:11

If you want to sort the list by multiple keys you can do the following:

my_list = [{'name':'Homer', 'age':39}, {'name':'Milhouse', 'age':10}, {'name':'Bart', 'age':10} ]
sortedlist = sorted(my_list , key=lambda elem: "%02d %s" % (elem['age'], elem['name']))

It is rather hackish, since it relies on converting the values into a single string representation for comparison, but it works as expected for numbers including negative ones (although you will need to format your string appropriately with zero paddings if you are using numbers)

@njzk2 2013-05-29 13:41:47

sorted using timsort which is stable, you can call sorted several times to have a sort on several criteria

@Permafacture 2013-08-23 21:05:24

njzk2's comment wasn't immediately clear to me so I found the following. You can just sort twice as njzk2 suggests, or pass multiple arguments to operator.itemgetter in the top answer. Link: stackoverflow.com/questions/5212870/…

@Winston Ewert 2013-12-15 04:55:55

No need to convert to string. Just return a tuple as the key.

@wouter bolsterlee 2015-04-24 13:59:58

Sorting multiple times is the easiest generic solution without hacks: stackoverflow.com/a/29849371/1805397

@Sandip Agarwal 2012-09-14 08:05:47

I tried something like this:

my_list.sort(key=lambda x: x['name'])

It worked for integers as well.

@hughdbrown 2009-07-17 18:22:08

Here is my answer to a related question on sorting by multiple columns. It also works for the degenerate case where the number of columns is only one.

@Owen 2008-09-16 14:52:14

You could use a custom comparison function, or you could pass in a function that calculates a custom sort key. That's usually more efficient as the key is only calculated once per item, while the comparison function would be called many more times.

You could do it this way:

def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey)

But the standard library contains a generic routine for getting items of arbitrary objects: itemgetter. So try this instead:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))

@efotinis 2008-09-16 14:43:51

import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

'key' is used to sort by an arbitrary value and 'itemgetter' sets that value to each item's 'name' attribute.

@Bartosz RadaczyƄski 2008-09-16 14:36:54

I guess you've meant:

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

This would be sorted like this:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))

@Matej 2008-09-16 14:31:52

You have to implement your own comparison function that will compare the dictionaries by values of name keys. See Sorting Mini-HOW TO from PythonInfo Wiki

Related Questions

Sponsored Content

42 Answered Questions

[SOLVED] How do I sort a dictionary by value?

43 Answered Questions

[SOLVED] How to merge two dictionaries in a single expression?

29 Answered Questions

[SOLVED] Finding the index of an item given a list containing it in Python

  • 2008-10-07 01:39:38
  • Eugene M
  • 3147246 View
  • 2595 Score
  • 29 Answer
  • Tags:   python list

27 Answered Questions

[SOLVED] Difference between append vs. extend list methods in Python

13 Answered Questions

[SOLVED] Iterating over dictionaries using 'for' loops

35 Answered Questions

[SOLVED] How do I check if a list is empty?

  • 2008-09-10 06:20:11
  • Ray Vega
  • 2107808 View
  • 3150 Score
  • 35 Answer
  • Tags:   python list

21 Answered Questions

[SOLVED] Check if a given key already exists in a dictionary

  • 2009-10-21 19:05:09
  • Mohan Gulati
  • 2719983 View
  • 2582 Score
  • 21 Answer
  • Tags:   python dictionary

14 Answered Questions

[SOLVED] Add new keys to a dictionary?

  • 2009-06-21 22:07:39
  • lfaraone
  • 2811303 View
  • 2170 Score
  • 14 Answer
  • Tags:   python dictionary

49 Answered Questions

[SOLVED] Sort a Map<Key, Value> by values

11 Answered Questions

[SOLVED] Use of *args and **kwargs

  • 2010-08-03 08:28:07
  • MacPython
  • 799390 View
  • 1280 Score
  • 11 Answer
  • Tags:   python args kwargs

Sponsored Content