web-dev-qa-db-fra.com

Python: comment trier une liste de dictionnaires par plusieurs valeurs?

Je veux d'abord trier une liste par valeur, puis par deuxième valeur. Y a-t-il un moyen facile de faire ceci? Voici un petit exemple:

A = [{'name':'john','age':45},
     {'name':'andi','age':23},
     {'name':'john','age':22},
     {'name':'paul','age':35},
     {'name':'john','age':21}]

Cette commande permet de trier cette liste par 'name':

sorted(A, key = lambda user: user['name'])

Mais comment puis-je trier cette liste par une deuxième valeur? Comme 'age' dans cet exemple.

Je veux un tri comme celui-ci (premier tri par 'name' puis trier par 'age'):

andi - 23
john - 21
john - 22
john - 45
paul - 35

Merci!

61
Joko
>>> 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'}]

Cela trie par un tuple des deux attributs, ce qui suit est équivalent et beaucoup plus rapide/plus propre:

>>> 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'}]

D'après les commentaires: @Bakuriu

Je parie qu'il n'y a pas de grande différence entre les deux, mais itemgetter évite un peu de surcharge car il extrait les clés et fait le Tuple pendant un seul opcode (CALL_FUNCTION), tout en appelant le lambda devra appeler la fonction, charger les différentes constantes (qui sont d'autres bytecodes) enfin appeler l'indice (BINARY_SUBSCR), construisez le Tuple et retournez-le ... c'est beaucoup plus de travail pour l'interpréteur.

Pour résumer: itemgetter maintient l'exécution entièrement au niveau C, donc c'est aussi rapide que possible.

89
jamylak
from operator import itemgetter

sorted(your_list, key=itemgetter('name', 'age'))
53
Jon Clements

Voici la solution générale alternative - elle trie les éléments de dict par clés et valeurs. L'avantage - pas besoin de spécifier de clés, et cela fonctionnerait toujours si certaines clés manquaient dans certains dictionnaires.

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)
0
vvladymyrov