J'ai une liste de dictionnaires et je souhaite que chaque élément soit trié en fonction d'une valeur de propriété spécifique.
Prenez en considération le tableau ci-dessous,
[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
Lorsque trié par name
, devrait devenir
[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
Il peut sembler plus propre d'utiliser une clé au lieu d'un cmp:
newlist = sorted(list_to_be_sorted, key=lambda k: k['name'])
ou comme suggéré par J.F.Sebastian et d’autres,
from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name'))
Pour être complet (comme indiqué dans les commentaires de fitzgeraldsteele), ajoutez reverse=True
pour trier par ordre décroissant.
newlist = sorted(l, key=itemgetter('name'), reverse=True)
import operator
Pour trier la liste des dictionnaires par clé = 'nom':
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'))
Si vous souhaitez trier la liste par plusieurs clés, vous pouvez procéder comme 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 bidon, puisqu'il repose sur la conversion des valeurs en une représentation de chaîne unique pour la comparaison, mais il fonctionne comme prévu pour les nombres incluant les nombres négatifs (bien que vous ayez besoin de formater votre chaîne de manière appropriée avec zéro padding si vous utilisez des nombres)
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) Édité pour ajouter:
Le nouvel argument key
est plus efficace et plus net. Une meilleure réponse ressemble maintenant à ceci:
my_list = sorted(my_list, key=lambda k: k['name'])
... le lambda est, IMO, plus facile à comprendre que operator.itemgetter
, mais YMMV.
import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))
'key' est utilisé pour trier selon une valeur arbitraire et 'itemgetter' définit cette valeur sur l'attribut 'name' de chaque élément.
Je suppose que vous avez voulu 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']))
En utilisant la transformation de Schwartzian de 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 transform
En informatique, la transformation de Schwartz est une programmation Perl idiome utilisé pour améliorer l’efficacité du tri d’une liste d’articles. Ce L'idiome est approprié pour le tri basé sur la comparaison lorsque l'ordre est réellement basé sur la commande d'une certaine propriété (la clé) de la éléments, où le calcul de cette propriété est une opération intensive que devrait être effectué un nombre minimal de fois. Le Schwartzian Transform est remarquable car il n'utilise pas de tableaux temporaires nommés.
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'])
Vous pouvez utiliser une fonction de comparaison personnalisée ou transmettre une fonction qui calcule une clé de tri personnalisée. C’est généralement plus efficace, car la clé n’est calculée qu’une fois par article, alors que la fonction de comparaison serait appelée beaucoup plus souvent.
Vous pouvez le 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 permettant d’obtenir des éléments d’objets arbitraires: itemgetter
. Alors essayez ceci à la place:
from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))
Vous devez implémenter votre propre fonction de comparaison qui comparera les dictionnaires en fonction des valeurs des clés de nom. Voir Tri de Mini-HOW TO dans PythonInfo Wiki
J'ai essayé quelque chose comme ça:
my_list.sort(key=lambda x: x['name'])
Cela a également fonctionné pour les nombres entiers.
parfois nous avons besoin d'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}]
Voici la solution générale alternative - il trie les éléments de dict par clés et par valeurs ..__ L'avantage - inutile de spécifier des clés, et cela fonctionnerait encore s'il manquait des clés 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)
Utiliser le paquetage 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 liste minuscule et une liste volumineuse (plus de 100 000 mots):
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
Disons que j'ai un dictionnaire D avec les éléments ci-dessous. Pour trier, il suffit d'utiliser l'argument de clé dans Trier 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
Voici ma réponse à une question connexe sur le tri en plusieurs colonnes . Cela fonctionne également pour le cas dégénéré où le nombre de colonnes est unique.
Si vous n'avez pas besoin de la list
d'origine de dictionaries
d'origine, vous pouvez la modifier sur place avec la méthode sort()
à l'aide d'une fonction de clé personnalisée.
Fonction clef:
def get_name(d):
""" Return the value of a key in a dictionary. """
return d["name"]
La list
à trier:
data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
Le trier sur place:
data_one.sort(key=get_name)
Si vous avez besoin de la list
d'origine, appelez la fonction sorted()
en lui passant la list
et la fonction clé, puis affectez la list
triée renvoyée à 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}]
Vous pouvez utiliser itemgetter , si vous souhaitez prendre en compte les performances. itemgetter est généralement plus rapide que lambda .
from operator import itemgetter
result = sorted(data, key=itemgetter('age')) # this will sort list by property order 'age'.
Vous pouvez utiliser le code suivant
sorted_dct = sorted(dct_name.items(), key = lambda x : x[1])