Comment trier une liste de dictionnaires par une valeur du dictionnaire en Python?

j'ai une liste de dictionnaires et je veux que chaque item soit trié par une valeur de propriété spécifique.

prendre en considération le tableau ci-dessous,

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

lorsqu'il est trié par name , doit devenir

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
1397
demandé sur masi 2008-09-16 18:27:47

17 réponses

Il peut sembler nettoyant à l'aide d'une clé au lieu d'un 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')) 

pour être complet (comme l'a souligné fitzgeraldsteele dans ses commentaires), Ajouter reverse=True pour trier les descendances

newlist = sorted(l, key=itemgetter('name'), reverse=True)
1873
répondu Mario F 2014-12-31 19:39:49
import operator

pour trier la liste des dictionnaires par clé= 'name':

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

pour trier la liste des dictionnaires par clé= "âge":

list_of_dicts.sort(key=operator.itemgetter('age'))
114
répondu cedbeu 2013-05-01 14:42:05

si vous voulez trier la liste par touches multiples, vous pouvez faire ce qui suit:

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

il est plutôt hackish, car il s'appuie sur la conversion des valeurs en une seule chaîne de représentation pour la comparaison, mais il fonctionne comme prévu pour les nombres y compris les négatifs (bien que vous aurez besoin de formater votre chaîne de manière appropriée avec ZERO paddings si vous utilisez des nombres)

42
répondu Dologan 2013-04-10 11:31:15
my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

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

my_list sera maintenant ce que vous voulez.

(3 ans plus tard) modifié pour ajouter:

le nouvel argument key est plus efficace et plus net. Une meilleure réponse ressemble maintenant à:

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

...la lambda est, IMO, plus facile à comprendre que operator.itemgetter , mais YMMV.

30
répondu pjz 2016-06-06 13:42:15
import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

" clé "est utilisé pour trier par une valeur arbitraire et "itemgetter' définit la valeur de chaque élément, l'attribut "name".

23
répondu efotinis 2008-09-16 14:43:51

je suppose que vous voulez dire:

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

ce serait trié comme ceci:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
17
répondu Bartosz Radaczyński 2008-09-16 14:36:54

utilisant Schwartzian transform from Perl,

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

faire

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

donne

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

Plus sur Perl Schwartzian transformer

en informatique, la Transformée de Schwartz est une Perl programmation l'idiome utilisé pour améliorer l'efficacité de tri d'une liste d'éléments. Ce l'idiome est approprié pour la comparaison de tri lorsque le la commande est en fait basé sur la commande d'une certaine propriété (la clé) de la éléments, où le calcul de cette propriété est un fonctionnement intensif que doit être effectué un nombre minimum de fois. Le Schwartzian Transform est notable en ce qu'il n'utilise pas les tableaux temporaires nommés.

15
répondu octoback 2013-05-27 11:21:03

vous pouvez utiliser une fonction de comparaison personnalisée, ou vous pouvez passer dans une fonction qui calcule une clé de tri personnalisée. C'est généralement plus efficace car la clé est calculée une seule fois par item, alors que la fonction de comparaison serait appelée beaucoup plus de fois.

Vous pourriez faire de cette façon:

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

mais la bibliothèque standard contient une routine générique pour obtenir des objets arbitraires: itemgetter . Essayez donc ceci à la place:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))
14
répondu Owen 2008-09-16 14:52:14

vous devez mettre en œuvre votre propre fonction de comparaison qui comparera les dictionnaires par les valeurs des clés de nom. Voir Tri Mini-HOW to from Pythoninfo Wiki

13
répondu Matej 2008-09-16 14:31:52
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']) 
12
répondu forzagreen 2017-03-17 10:29:50

j'ai essayé quelque chose comme ceci:

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

ça marchait aussi pour les entiers.

8
répondu Sandip Agarwal 2013-04-10 11:30:29

Voici la solution générale alternative - il trie des éléments de dict par des clés et des valeurs. L'avantage de celui - ci- pas besoin de spécifier les clés, et il fonctionne encore si certaines clés sont manquantes 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)
sorted(A, key=sort_key_func)
7
répondu vvladymyrov 2015-01-22 17:21:17

utiliser le paquet pandas est une autre méthode, bien que son exécution à grande échelle soit beaucoup plus lente que les méthodes plus traditionnelles proposées par d'autres:

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()

voici quelques valeurs de référence pour une petite liste et une grande (100k+) liste de 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
6
répondu abby sobh 2016-11-09 16:58:57

parfois, nous devons utiliser lower() par exemple

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}]
5
répondu uingtea 2017-07-14 03:21:08

disons que j'ai un dictionnaire D avec les éléments ci-dessous. Pour trier il suffit d'utiliser l'argument clé dans tried pour passer la fonction personnalisée comme ci-dessous

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

3
répondu SuaveShank 2014-04-16 07:35:10

Voici ma réponse à une question connexe sur le tri par colonnes multiples . Il travaille également pour le cas dégénéré où le nombre de colonnes n'est qu'un.

2
répondu hughdbrown 2017-05-23 12:34:51

si vous n'avez pas besoin de l'original list de dictionaries , vous pouvez le modifier en place avec la méthode sort() en utilisant une fonction de clé personnalisée.

fonction clé:

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

    return d["name"]

le list à trier:

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

tri en place:

data_one.sort(key=get_name)

si vous avez besoin de l'original list , appelez la fonction sorted() en lui passant le list et la fonction clé, puis attribuer le retour trié list à une nouvelle variable:

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

Impression data_one et new_data .

>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
0
répondu srig 2017-12-19 17:31:30