Question

J'ai une liste de dictionnaires et je souhaite que chaque élément soit trié selon des valeurs de propriété spécifiques.

Prenez en compte le tableau ci-dessous,

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

Une fois trié par nom , devrait devenir

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
Était-ce utile?

La solution

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)

Autres conseils

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 en fonction de plusieurs clés, procédez 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']))

C’est plutôt hackish, car il faut convertir les valeurs en une représentation sous forme de chaîne unique à des fins de comparaison, mais cela fonctionne normalement pour les nombres contenant des nombres négatifs (bien que vous ayez besoin de formater votre chaîne avec zéro padding si vous utilisez chiffres)

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

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

ma_liste sera maintenant ce que vous voulez.

(3 ans plus tard) Modification:

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

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

"clé" sert à trier selon une valeur arbitraire et "itemgetter" définit cette valeur sur l'attribut "nom" de chaque élément.

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

Je suppose que vous vouliez dire:

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

Ceci serait trié comme ceci:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))

Utilisation de la transformation de Schwartzian à partir 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'}]

Pour en savoir plus sur la transformation Perl Schwartzian

  

En informatique, la transformation de Schwartzian est une programmation Perl   idiome utilisé pour améliorer l’efficacité du tri d’une liste d’articles. Ce   idiome est approprié pour le tri basé sur la comparaison lorsque la commande 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   devrait être effectué un nombre minimal de fois. Le schwartzien   Transform est remarquable car il n'utilise pas de tableaux temporaires nommés.

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, tandis que la fonction de comparaison est appelée encore plusieurs fois.

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 pour obtenir des éléments d'objets arbitraires: itemgetter . Alors essayez plutôt ceci:

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 du mini-guide d'utilisation du wiki PythonInfo

Voici la solution générale alternative: il trie les éléments de dict par clés et par valeurs. L’avantage de ce logiciel est qu’il n’est pas nécessaire de spécifier des clés. Cela fonctionnerait quand même 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)
sorted(A, key=sort_key_func)

nous avons parfois 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}]

J'ai essayé quelque chose comme ça:

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

Cela a également fonctionné pour les entiers.

L’utilisation du 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 liste minuscule et une liste volumineuse (plus de 100 Ko):

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 clé de la commande 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

https://wiki.python.org/moin/HowTo/Sorting/# Fonctions_ clés

Voici ma réponse à une question connexe sur le tri par 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 liste d'origine des dictionnaires , vous pouvez la modifier sur place à l'aide de la méthode sort () à l'aide d'une commande personnalisée. fonction clé.

Fonction clé:

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

    return d["name"]

La liste à trier:

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

Tri sur place:

data_one.sort(key=get_name)

Si vous avez besoin de la liste d'origine , appelez la fonction triée () en lui passant la liste et la fonction de clé, puis affectez la valeur renvoyée. liste triée dans une nouvelle variable:

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

Impression de data_one et de 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])
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top