it-swarm-pt.tech

Como faço para classificar uma lista de dicionários por um valor do dicionário?

Eu tenho uma lista de dicionários e quero que cada item seja classificado por valores de propriedade específicos.

Leve em consideração o array abaixo,

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

Quando classificado por name, deve se tornar

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

Pode parecer mais limpo usando uma chave em vez de um cmp:

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

ou como J. F. Sebastian e outros sugeriram,

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

Para completar (como apontado nos comentários por fitzgeraldsteele), adicione reverse=True para ordenar decrescente

newlist = sorted(l, key=itemgetter('name'), reverse=True)
2038
Mario F
import operator

Para classificar a lista de dicionários por key = 'name':

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

Para classificar a lista de dicionários por key = 'age':

list_of_dicts.sort(key=operator.itemgetter('age'))
123
vemury

Se você quiser classificar a lista por várias chaves, poderá fazer o seguinte:

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

Ele é bastante invasivo, pois depende da conversão dos valores em uma única representação de seqüência de caracteres para comparação, mas funciona como esperado para números que incluem números negativos (embora seja necessário formatá-la apropriadamente com preenchimento zero se você estiver usando 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 agora será o que você deseja.

(3 anos depois) Editado para adicionar:

O novo argumento key é mais eficiente e mais limpo. Uma resposta melhor agora parece:

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

... o lambda é, IMO, mais fácil de entender do que operator.itemgetter, mas YMMV.

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

'key' é usado para classificar por um valor arbitrário e 'itemgetter' define esse valor para o atributo 'name' de cada item.

26
efotinis

Eu acho que você quis dizer:

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

Isso seria classificado assim:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
18
Bartosz Radaczyński

Usando Schwartzian transformar de Perl,

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

faz

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

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

Mais sobre Perl Schwartzian transform

Na ciência da computação, a transformação Schwartziana é uma linguagem de programação Perl usada para melhorar a eficiência da classificação de uma lista de itens. Esse idioma É apropriado para classificação baseada em comparação quando a ordenação é Baseada na ordenação de uma determinada propriedade (a chave) dos elementos , Onde a computação dessa propriedade é uma operação intensiva que deve ser executada um número mínimo de vezes. O Schwartzian Transform é notável em que ele não usa matrizes temporárias nomeadas.

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

Você pode usar uma função de comparação personalizada ou pode passar uma função que calcule uma chave de classificação personalizada. Isso geralmente é mais eficiente, pois a chave é calculada apenas uma vez por item, enquanto a função de comparação seria chamada muito mais vezes.

Você poderia fazer assim:

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

Mas a biblioteca padrão contém uma rotina genérica para obter itens de objetos arbitrários: itemgetter. Então tente isso:

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

Você tem que implementar sua própria função de comparação que irá comparar os dicionários por valores de chaves de nome. Veja Classificando o Mini-COMO do Wiki do PythonInfo

14
Matej

Eu tentei algo assim:

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

Funcionou para inteiros também.

10
Sandip Agarwal

Às vezes precisamos usar lower() por exemplo

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

Aqui está a solução geral alternativa - classifica os elementos do dict por chaves e valores. A vantagem disso - não é necessário especificar chaves, e ainda funcionaria se algumas chaves estivessem faltando em alguns dicionários.

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 o pacote pandas é outro método, embora seu tempo de execução em larga escala seja muito mais lento do que os métodos mais tradicionais propostos por outros:

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

Aqui estão alguns valores de referência para uma lista pequena e uma lista grande (100k +) de ditos:

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

Vamos dizer que eu tenho um dicionário D com elementos abaixo. Para classificar apenas use argumento-chave em classificado para passar a função personalizada como abaixo

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

Aqui está minha resposta para uma questão relacionada na classificação por várias colunas . Também funciona para o caso degenerado em que o número de colunas é apenas um.

4
hughdbrown

Se você não precisa da list original de dictionaries, você pode modificá-la no local com o método sort() usando uma função de chave personalizada.

Função chave:

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

    return d["name"]

O list a ser classificado:

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

Classificando-o no local:

data_one.sort(key=get_name)

Se você precisar da list original, chame a função sorted() passando a list e a função-chave e, em seguida, atribua a list classificada e retornada a uma nova variável:

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

Imprimindo data_one e 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

Você pode usar itemgetter , se quiser considerar o desempenho. itemgetter tipicamente roda bit mais rápido que lambda .

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

Você pode usar o seguinte código

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