web-development-kb-es.site

¿Cómo clasifico una lista de diccionarios por un valor del diccionario?

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

Tenga en cuenta la matriz a continuación,

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

Cuando se ordena por name, debería convertirse

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

Puede verse más limpio usando una tecla 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 para ordenar descendente

newlist = sorted(l, key=itemgetter('name'), reverse=True)
2038
Mario F
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'))
123
vemury

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 más bien pirata, ya que se basa en convertir los valores en una representación de cadena única para comparación, pero funciona como se espera para los números que incluyen los negativos (aunque necesitará usar el formato de la cadena adecuadamente con cero rellenos si utiliza números)

43
Dologan
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 quieras.

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

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

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

... la lambda es, IMO, más fácil de entender que operator.itemgetter, pero YMMV.

38
pjz
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 'nombre' de cada elemento.

26
efotinis

Supongo que has querido 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']))
18

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 Perl Schwartzian transform

En informática, la transformación de Schwartz es un lenguaje de programación De Perl que se utiliza para mejorar la eficacia de la clasificación de una lista de elementos. Este modismo Es apropiado para la clasificación basada en comparación cuando la ordenación es En realidad se basa en la ordenación de una determinada propiedad (la clave) de los elementos , Donde calcular esa propiedad es una operación intensiva que se debe realizar un número mínimo de veces. La transformación Schwartziana Es notable porque no utiliza matrices temporales con nombre.

17
octoback
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']) 
15
forzagreen

Podría usar una función de comparación personalizada, o podría pasar a 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 llamará 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 intente esto en su lugar:

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

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

14
Matej

Intenté algo como esto:

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

Funcionó para enteros también.

10
Sandip Agarwal

alguna vez 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}]
9
uingtea

Aquí está la solución general alternativa: ordena los elementos de dictado por claves y valores. La ventaja de ello: 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)
9
vvladymyrov

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 (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
8
abby sobh

Digamos que tengo un Diccionario D con elementos a continuación. Para ordenar solo 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

5
Shank_Transformer

Aquí está mi respuesta a una pregunta relacionada sobre la clasificación por columnas múltiples . También funciona para el caso degenerado donde el número de columnas es solo una.

4
hughdbrown

Si no necesita el list original de dictionaries, puede modificarlo in situ con el método sort() 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"]

La 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 necesita el list original, llame a la función sorted() pasándole el list y la función de la tecla, luego asigne el list ordenado devuelto a una nueva variable:

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

Imprimiendo 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}]
2
Srisaila

Puede usar itemgetter , si desea considerar el rendimiento. itemgetter normalmente se ejecuta 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'.
1
vikas0713

Puedes usar el siguiente código

sorted_dct = sorted(dct_name.items(), key = lambda x : x[1])
0
Loochie