How do I sort a list of dictionaries by a value of the dictionary?

1,041,459

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']) 
Share:
1,041,459
masi
Author by

masi

Updated on April 11, 2022

Comments

  • masi
    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
      Claudiu almost 4 years
      Reading 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
    jfs over 15 years
    Using key is not only cleaner but more effecient too.
  • Mario F
    Mario F over 14 years
    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
    Philluminati over 14 years
    if the sort value is a number you could say: lambda k: (k['age'] * -1) to get a reverse sort
  • monojohnny
    monojohnny about 14 years
    Anyway to combine name and age ? (like in SQL ORDER BY name,age ?)
  • radicand
    radicand almost 12 years
    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
    Bakuriu over 11 years
    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.
  • njzk2
    njzk2 almost 11 years
    sorted using timsort which is stable, you can call sorted several times to have a sort on several criteria
  • Permafacture
    Permafacture over 10 years
    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/…
  • Claudiu
    Claudiu over 10 years
    @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.
  • Winston Ewert
    Winston Ewert over 10 years
    No need to convert to string. Just return a tuple as the key.
  • TTT
    TTT about 10 years
    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?
  • Antti Haapala -- Слава Україні
    Antti Haapala -- Слава Україні about 9 years
    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.
  • Kevin
    Kevin about 9 years
    @TTT: See the library documentation for list and friends.
  • wouter bolsterlee
    wouter bolsterlee about 9 years
    Sorting multiple times is the easiest generic solution without hacks: stackoverflow.com/a/29849371/1805397
  • clp2
    clp2 over 7 years
    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
    abby sobh over 7 years
    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.
  • webenformasyon
    webenformasyon over 4 years
    in 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
    Peter Mortensen almost 4 years
    This relies too much on the link. Can you provide a more complete answer?
  • Peter Mortensen
    Peter Mortensen almost 4 years
    Why do we need to use lower() in this case?
  • Peter Mortensen
    Peter Mortensen almost 4 years
    What 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
    G.J over 3 years
    Proper anwers are already provided by other contributors as well. Feel free to either keep the link, or delete the answer.
  • Sam
    Sam over 3 years
    what 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
    Notre over 3 years
    I'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
    sattva_venu over 3 years
    what if we don't know the value of key?
  • Notre
    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
    Andrew over 2 years
    operator.itemgetter worked for me, the first option didn't work or maybe I didn't fill in the right info... lambda? d: ?
  • reza_khalafi
    reza_khalafi about 2 years
    list indices must be integers or slices, not str
  • ciurlaro
    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
    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 using itemgetter you could use a custom function and do whatever you want there.
  • Bakuriu
    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 on D, E with reverse=True, then on C with reverse=False and finally on A,B with reverse=True.
  • ciurlaro
    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