valeurs - trier une liste de dictionnaire python




Comment trier une liste de dictionnaires par valeurs du dictionnaire en Python? (12)

Disons que je ai un dictionnaire D avec les éléments ci-dessous. Pour trier utiliser simplement l'argument clé dans trié 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

J'ai obtenu une liste de dictionnaires et je veux que cela soit trié par une valeur de ce dictionnaire.

Ce

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

trié par nom, devrait devenir

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

En utilisant la transformation 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 schwartzienne est un idiome de programmation Perl utilisé pour améliorer l'efficacité du tri d'une liste d'éléments. Cet idiome est approprié pour le tri basé sur la comparaison lorsque la commande est réellement basée sur l'ordre d'une certaine propriété (la clé) des éléments, où le calcul de cette propriété est une opération intensive qui devrait être effectuée un nombre minimal de fois. La Transformation schwartzienne est remarquable en ce qu'elle n'utilise pas de tableaux temporaires nommés.


J'ai essayé quelque chose comme ça:

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

Cela a fonctionné aussi pour les entiers.


Je suppose que tu as voulu dire:

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

Cela serait trié comme ceci:

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

Si vous souhaitez trier la liste par plusieurs clés, vous pouvez effectuer les opérations suivantes:

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, puisqu'il repose sur la conversion des valeurs en une seule représentation de chaîne, mais cela fonctionne comme prévu pour les nombres incluant les négatifs (bien que vous ayez besoin de formater correctement votre chaîne avec zéro paddings si vous utilisez des nombres)


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 liste minuscule et une grande liste (100k +) 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

Voici la solution générale alternative - il trie les éléments de dict par les clés et les valeurs. L'avantage de cela - pas besoin de spécifier des clés, et cela fonctionnerait encore si certaines clés manquent 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)


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

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

import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

'key' est utilisé pour trier par une valeur arbitraire et 'itemgetter' définit cette valeur pour l'attribut 'name' de chaque élément.


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) Edité pour ajouter:

Le nouvel argument key est plus efficace et plus propre. 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.





data-structures