How do I sort a list of dictionaries by a value of the dictionary?
Solution 1
The sorted()
function takes a key=
parameter
newlist = sorted(list_to_be_sorted, key=lambda d: d['name'])
Alternatively, you can use operator.itemgetter
instead of defining the function yourself
from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name'))
For completeness, add reverse=True
to sort in descending order
newlist = sorted(list_to_be_sorted, key=itemgetter('name'), reverse=True)
Solution 2
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'))
Solution 3
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.
Or better:
Since Python 2.4, there's a key
argument is both more efficient and neater:
my_list = sorted(my_list, key=lambda k: k['name'])
...the lambda is, IMO, easier to understand than operator.itemgetter
, but your mileage may vary.
Solution 4
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).
Solution 5
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'])
masi
Updated on April 11, 2022Comments
-
masi about 2 years
How do I sort a list of dictionaries by a specific key's value? Given:
[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
When sorted by
name
, it should become:[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
-
Claudiu almost 4 yearsReading the answer and looking on operator.itemgetter. Can I sort on multiple value in the same process (for example we have
[{'name':'Bart', 'age':10, 'note':3},{'name':'Homer','age':10,'note':2},{'name':'Vasile','age':20,'note':3}]
And to use:from operator import itemgetter newlist = sorted(old_list, key=itemgetter(-'note','name')
EDIT: Tested, and it is working but I don't know how to make note DESC and name ASC.
-
-
jfs over 15 yearsUsing key is not only cleaner but more effecient too.
-
Mario F over 14 yearsThe 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 over 14 yearsif the sort value is a number you could say: lambda k: (k['age'] * -1) to get a reverse sort
-
monojohnny about 14 yearsAnyway to combine name and age ? (like in SQL ORDER BY name,age ?)
-
radicand almost 12 yearsThis also applies to a list of tuples, if you use
itemgetter(i)
wherei
is the index of the tuple element to sort on. -
Bakuriu over 11 years
itemgetter
accepts more than one argument:itemgetter(1,2,3)
is a function that return a tuple likeobj[1], obj[2], obj[3]
, so you can use it to do complex sorts. -
njzk2 almost 11 yearssorted using timsort which is stable, you can call sorted several times to have a sort on several criteria
-
Permafacture over 10 yearsnjzk2'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/…
-
Claudiu over 10 years@monojohnny: yes, just have the key return a tuple,
key=lambda k: (k['name'], k['age'])
. (orkey=itemgetter('name', 'age')
). tuple'scmp
will compare each element in turn. it's bloody brilliant. -
Winston Ewert over 10 yearsNo need to convert to string. Just return a tuple as the key.
-
TTT about 10 yearsIn the documentation (docs.python.org/2/tutorial/datastructures.html) the optional
key
argument forlist.sort()
is not described. Any idea where to find that? -
Antti Haapala -- Слава Україні about 9 yearsPython 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. -
Kevin about 9 years@TTT: See the library documentation for
list
and friends. -
wouter bolsterlee about 9 yearsSorting multiple times is the easiest generic solution without hacks: stackoverflow.com/a/29849371/1805397
-
clp2 over 7 yearsI 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 over 7 yearsYou'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.
-
webenformasyon over 4 yearsin case of unicode strings
import locale / locale.setlocale(locale.LC_ALL, "") / newlist = sorted(list_to_be_sorted, key=lambda k: locale.strxfrm(k['name']))
works inspired from stackoverflow.com/questions/1097908/… -
Peter Mortensen almost 4 yearsThis relies too much on the link. Can you provide a more complete answer?
-
Peter Mortensen almost 4 yearsWhy do we need to use lower() in this case?
-
Peter Mortensen almost 4 yearsWhat do you mean by "sorts elements of a dict by keys and values"? In what way is it sorting? Where do the values come in?
-
G.J over 3 yearsProper anwers are already provided by other contributors as well. Feel free to either keep the link, or delete the answer.
-
Sam over 3 yearswhat could be done if the key is unknown and keeps changing?I mean list of dicts with just one key and value but the key and value could not be defined as they keep changing.
-
Notre over 3 yearsI'd need more of an example to look at. Try submitting a possible solution on the codereview stackexchange and asking if there's a better way.
-
sattva_venu over 3 yearswhat if we don't know the value of key?
-
Notre about 3 years@Sam if you want to sort by the value of the single key in the dict, even if you don't know the key, you can do
key=lambda k: list(k.values())[0]
-
Andrew over 2 yearsoperator.itemgetter worked for me, the first option didn't work or maybe I didn't fill in the right info... lambda? d: ?
-
reza_khalafi about 2 yearslist indices must be integers or slices, not str
-
ciurlaro about 2 years@Bakuriu is there any way to do complex sorts with both ascending and descending order? e.g.
key=itemgetter("speed", "color", "cost"), reverse=(True, False, True)
-
Bakuriu about 2 years@ciurlaro Not that I know of. In order to make that work you'd first have to
map
the values in a way that make the fields you want sort in the opposite direction, then use a plain sort by those fields and at the end "un-wrap" the values. Obviously instead of usingitemgetter
you could use a custom function and do whatever you want there. -
Bakuriu about 2 years@ciurlaro Note that in python sorting is stable, so say you want to achieve the equivalent of
key=itemgetter('A', 'B', 'C', 'D', 'E'), reverse=(True, True, False, True, True)
you could do that by sorting 3 times: first onD, E
withreverse=True
, then onC
withreverse=False
and finally onA,B
withreverse=True
. -
ciurlaro about 2 years@Bakuriu I found this answer stackoverflow.com/a/56842689/3004162 that worked to achieve what I wanted. Still far from a beauty of a builtin function unfortunately, but that's the best I found