¿Cómo clasifico una lista de diccionarios por el valor de una clave específica? Dado:

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

Cuando se ordena por name, debería convertirse en:

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

La sorted()función toma un key=parámetro

newlist = sorted(list_to_be_sorted, key=lambda d: d['name']) 

Alternativamente, puede usar operator.itemgetteren lugar de definir la función usted mismo

from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name')) 

Para completar, agregue reverse=Truepara ordenar en orden descendente

newlist = sorted(list_to_be_sorted, key=itemgetter('name'), reverse=True)
import operator

Para ordenar la lista de diccionarios por key='name':

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

Para ordenar la lista de diccionarios por clave='edad':

list_of_dicts.sort(key=operator.itemgetter('age'))
my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

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

my_listahora será lo que quieras.

O mejor:

Desde Python 2.4, hay un keyargumento que es más eficiente y ordenado:

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

... la lambda es, en mi opinión, más fácil de entender que operator.itemgetter, pero su kilometraje puede variar.

Si desea ordenar la lista por varias claves, puede hacer lo siguiente:

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

Es bastante complicado, ya que se basa en convertir los valores en una representación de una sola cadena para la comparación, pero funciona como se espera para los números, incluidos los negativos (aunque deberá formatear su cadena de forma adecuada con cero rellenos si está usando números).

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' se usa para ordenar por un valor arbitrario y 'itemgetter' establece ese valor en el atributo 'name' de cada elemento.

Supongo que quisiste decir:

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

Esto se ordenaría así:

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

Usando la transformada de Schwartzian de Perl,

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

hacer

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

da

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

Más sobre la transformación de Perl Schwartzian:

In computer science, the Schwartzian transform is a Perl programming idiom used to improve the efficiency of sorting a list of items. This idiom is appropriate for comparison-based sorting when the ordering is actually based on the ordering of a certain property (the key) of the elements, where computing that property is an intensive operation that should be performed a minimal number of times. The Schwartzian Transform is notable in that it does not use named temporary arrays.

Podría usar una función de comparación personalizada, o podría pasar una función que calcula una clave de clasificación personalizada. Eso suele ser más eficiente ya que la clave solo se calcula una vez por elemento, mientras que la función de comparación se llama muchas veces más.

Podrías hacerlo de esta manera:

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

Pero la biblioteca estándar contiene una rutina genérica para obtener elementos de objetos arbitrarios: itemgetter. Así que prueba esto en su lugar:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))

Debe implementar su propia función de comparación que comparará los diccionarios por valores de claves de nombre. Ver Clasificar Mini-HOW TO de PythonInfo Wiki

A veces necesitamos usar lower(). Por ejemplo,

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

Usar el paquete Pandas es otro método, aunque su tiempo de ejecución a gran escala es mucho más lento que los métodos más tradicionales propuestos por otros:

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

Aquí hay algunos valores de referencia para una lista pequeña y una lista grande (más de 100k) de dictados:

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

Aquí está la solución general alternativa: ordena los elementos de un dict por claves y valores.

La ventaja de esto: no es necesario especificar claves, y aún funcionaría si faltan algunas claves en algunos de los diccionarios.

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)

Digamos que tengo un diccionario Dcon los siguientes elementos. Para ordenar, simplemente use el argumento clave sortedpara pasar una función personalizada como se muestra a continuación:

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

Mira esto .

Si no necesita el original listde dictionaries, puede modificarlo en el lugar con el sort()método usando una función de tecla personalizada.

Función de la tecla:

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

    return d["name"]

El listque se va a ordenar:

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

Clasificándolo en el lugar:

data_one.sort(key=get_name)

Si necesita el original list, llame a la sorted()función pasándole la función listy la tecla, luego asigne el devuelto ordenado lista una nueva variable:

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

Imprenta data_oney new_data.

>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]

He sido un gran admirador de un filtro con lambda. Sin embargo, no es la mejor opción si considera la complejidad del tiempo.

Primera opción

sorted_list = sorted(list_to_sort, key= lambda x: x['name'])
# Returns list of values

Segunda opción

list_to_sort.sort(key=operator.itemgetter('name'))
# Edits the list, and does not return a new list

Comparación rápida de tiempos de ejecución

# First option
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" "sorted_l = sorted(list_to_sort, key=lambda e: e['name'])"

1000000 loops, best of 3: 0.736 µsec per loop

# Second option
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" -s "import operator" "list_to_sort.sort(key=operator.itemgetter('name'))"

1000000 loops, best of 3: 0.438 µsec per loop

Si el rendimiento es una preocupación, usaría operator.itemgetteren lugar de lambdacomo funciones integradas que funcionan más rápido que las funciones hechas a mano. La itemgetterfunción parece funcionar aproximadamente un 20 % más rápido que lambdasegún mis pruebas.

De https://wiki.python.org/moin/PythonSpeed :

Likewise, the builtin functions run faster than hand-built equivalents. For example, map(operator.add, v1, v2) is faster than map(lambda x,y: x+y, v1, v2).

Aquí hay una comparación de la velocidad de clasificación usando lambdavs.itemgetter

import random
import operator

# Create a list of 100 dicts with random 8-letter names and random ages from 0 to 100.
l = [{'name': ''.join(random.choices(string.ascii_lowercase, k=8)), 'age': random.randint(0, 100)} for i in range(100)]

# Test the performance with a lambda function sorting on name
%timeit sorted(l, key=lambda x: x['name'])
13 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# Test the performance with itemgetter sorting on name
%timeit sorted(l, key=operator.itemgetter('name'))
10.7 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# Check that each technique produces the same sort order
sorted(l, key=lambda x: x['name']) == sorted(l, key=operator.itemgetter('name'))
True

Ambas técnicas clasifican la lista en el mismo orden (verificado por la ejecución de la declaración final en el bloque de código), pero la primera es un poco más rápida.

Como lo indicó @Claudiu a @monojohnny en la sección de comentarios de esta respuesta ,
dado:

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

para ordenar la lista de diccionarios por clave 'age'( 'name'
como en la instrucción SQL ORDER BY age, name), puede usar:

newlist = sorted( list_to_be_sorted, key=lambda k: (k['age'], k['name']) )

o, igualmente

import operator
newlist = sorted( list_to_be_sorted, key=operator.itemgetter('age','name') )

print(newlist)

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