Python: How to sort a list of dictionaries by several values?
Question:
I want to sort a list at first by a value and then by a second value. Is there an easy way to do this? Here is a small example:
A = [{'name':'john','age':45},
{'name':'andi','age':23},
{'name':'john','age':22},
{'name':'paul','age':35},
{'name':'john','age':21}]
This command is for sorting this list by 'name'
:
sorted(A, key = lambda user: user['name'])
But how I can sort this list by a second value? Like 'age'
in this example.
I want a sorting like this (first sort by 'name'
and then sort by 'age'
):
andi - 23
john - 21
john - 22
john - 45
paul - 35
Thanks!
Answers:
>>> A = [{'name':'john','age':45},
{'name':'andi','age':23},
{'name':'john','age':22},
{'name':'paul','age':35},
{'name':'john','age':21}]
>>> sorted(A, key = lambda user: (user['name'], user['age']))
[{'age': 23, 'name': 'andi'}, {'age': 21, 'name': 'john'}, {'age': 22, 'name': 'john'}, {'age': 45, 'name': 'john'}, {'age': 35, 'name': 'paul'}]
This sorts by a tuple of the two attributes, the following is equivalent and much faster/cleaner:
>>> from operator import itemgetter
>>> sorted(A, key=itemgetter('name', 'age'))
[{'age': 23, 'name': 'andi'}, {'age': 21, 'name': 'john'}, {'age': 22, 'name': 'john'}, {'age': 45, 'name': 'john'}, {'age': 35, 'name': 'paul'}]
From the comments: @Bakuriu
I bet there is not a big difference between the two, but itemgetter
avoids a bit of overhead because it extracts the keys and make the tuple
during a single opcode(CALL_FUNCTION
), while calling the lambda
will have to call the function, load the various constants(which are other bytecodes) finally call the subscript (BINARY_SUBSCR
), build the tuple
and return it… that’s a lot more work for the interpreter.
To summarize: itemgetter
keeps the execution fully on the C
level, so it’s as fast as possible.
from operator import itemgetter
sorted(your_list, key=itemgetter('name', 'age'))
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)
I want to sort a list at first by a value and then by a second value. Is there an easy way to do this? Here is a small example:
A = [{'name':'john','age':45},
{'name':'andi','age':23},
{'name':'john','age':22},
{'name':'paul','age':35},
{'name':'john','age':21}]
This command is for sorting this list by 'name'
:
sorted(A, key = lambda user: user['name'])
But how I can sort this list by a second value? Like 'age'
in this example.
I want a sorting like this (first sort by 'name'
and then sort by 'age'
):
andi - 23
john - 21
john - 22
john - 45
paul - 35
Thanks!
>>> A = [{'name':'john','age':45},
{'name':'andi','age':23},
{'name':'john','age':22},
{'name':'paul','age':35},
{'name':'john','age':21}]
>>> sorted(A, key = lambda user: (user['name'], user['age']))
[{'age': 23, 'name': 'andi'}, {'age': 21, 'name': 'john'}, {'age': 22, 'name': 'john'}, {'age': 45, 'name': 'john'}, {'age': 35, 'name': 'paul'}]
This sorts by a tuple of the two attributes, the following is equivalent and much faster/cleaner:
>>> from operator import itemgetter
>>> sorted(A, key=itemgetter('name', 'age'))
[{'age': 23, 'name': 'andi'}, {'age': 21, 'name': 'john'}, {'age': 22, 'name': 'john'}, {'age': 45, 'name': 'john'}, {'age': 35, 'name': 'paul'}]
From the comments: @Bakuriu
I bet there is not a big difference between the two, but
itemgetter
avoids a bit of overhead because it extracts the keys and make thetuple
during a single opcode(CALL_FUNCTION
), while calling thelambda
will have to call the function, load the various constants(which are other bytecodes) finally call the subscript (BINARY_SUBSCR
), build thetuple
and return it… that’s a lot more work for the interpreter.
To summarize: itemgetter
keeps the execution fully on the C
level, so it’s as fast as possible.
from operator import itemgetter
sorted(your_list, key=itemgetter('name', 'age'))
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)