Pregunta

Tengo una lista de diccionarios y quiero que cada elemento se ordene según valores de propiedad específicos.

Tenga en cuenta la siguiente matriz,

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

Cuando se ordena por name, debe convertirse

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
¿Fue útil?

Solución

Puede verse más limpio usando una clave en lugar de un cmp:

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

o como sugirieron J.F.Sebastian y otros,

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

Para completar (como se señala en los comentarios de fitzgeraldsteele), agregue reverse=True ordenar de forma descendente

newlist = sorted(l, key=itemgetter('name'), reverse=True)

Otros consejos

import operator

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

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

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 cadena única para comparar, pero funciona como se esperaba para números, incluidos los negativos (aunque necesitará formatear su cadena apropiadamente con rellenos de ceros si está usando números)

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

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

my_list ahora será lo que deseas.

(3 años después) Editado para agregar:

El nuevo key El argumento es más eficiente y ordenado.Una mejor respuesta ahora parece:

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 YMMV.

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

'clave' se utiliza para ordenar por un valor arbitrario y 'itemgetter' establece ese valor en el atributo 'nombre' de cada elemento.

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

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 en Transformada de Perl Schwartzian

En informática, la transformación de Schwartzian es un idioma de programación de Perl utilizado para mejorar la eficiencia de clasificar una lista de elementos.Este idioma es apropiado para la clasificación basada en la comparación cuando el pedido se basa en el orden de una determinada propiedad (la clave) de los elementos, donde la computación de esa propiedad es una operación intensiva que debe realizarse un número mínimo de veces.La transformación de Schwartzian es notable porque no usa matrices temporales con nombre.

Podría usar una función de comparación personalizada o podría pasar una función que calcule una clave de clasificación personalizada.Esto 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 llamaría muchas más veces.

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.Entonces 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 Ordenando Mini-CÓMO desde PythonInfo Wiki

Aquí está la solución general alternativa: ordena los elementos de dict por claves y valores.La ventaja de esto es que no es necesario especificar claves y aún funcionaría si faltan algunas claves en algunos 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)

en algún momento 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}]

Intenté algo como esto:

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

También funcionó para números enteros.

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

A continuación se muestran algunos valores de referencia para una lista pequeña y una lista grande (más de 100.000) 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

Digamos que tengo un Diccionario D con los elementos siguientes.Para ordenar simplemente use el argumento clave en ordenado para pasar la 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

https://wiki.python.org/moin/HowTo/Sorting/#Key_Functions

Aquí está mi respuesta a una pregunta relacionada sobre ordenar por varias columnas.También funciona para el caso degenerado donde el número de columnas es solo uno.

Si no necesitas el original list de dictionaries, podrías modificarlo en el lugar con sort() método utilizando 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 list a ordenar:

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

Clasificándolo en el lugar:

data_one.sort(key=get_name)

Si necesitas el original list, llama a sorted() función pasándole el list y la función clave, luego asigne el orden devuelto list a una nueva variable:

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

Impresión data_one y new_data.

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

Puedes usar captador de artículos ,si quieres considerar el rendimiento. captador de artículos normalmente corre un poco más rápido que lambda.

from operator import itemgetter
result = sorted(data, key=itemgetter('age'))  # this will sort list by property order 'age'.

Puedes usar el siguiente código

sorted_dct = sorted(dct_name.items(), key = lambda x : x[1])
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top