Como ordeno um dicionário por valor?


3422

Eu tenho um dicionário de valores lido de dois campos em um banco de dados: um campo de seqüência de caracteres e um campo numérico. O campo string é exclusivo, portanto essa é a chave do dicionário.

Posso classificar as chaves, mas como posso classificar com base nos valores?

Nota: Li a pergunta Stack Overflow aqui. Como classifico uma lista de dicionários por um valor do dicionário? e provavelmente poderia alterar meu código para ter uma lista de dicionários, mas como eu realmente não preciso de uma lista de dicionários, eu queria saber se existe uma solução mais simples para classificar em ordem crescente ou decrescente.


9
A estrutura de dados do dicionário não tem ordem inerente. Você pode iterar através dele, mas não há nada para garantir que a iteração siga uma ordem específica. Isso ocorre por design, portanto, sua melhor aposta é provavelmente usar a estrutura de dados do ano para representação.
Daishiman

135
"Sorted ()" pode operar em dicionários (e retorna uma lista de chaves ordenadas), então acho que ele está ciente disso. Sem conhecer o programa dele, é absurdo dizer a alguém que está usando a estrutura de dados errada. Se pesquisas necessárias são necessárias 90% do tempo, então provavelmente é o que você deseja.
22413 Bobpaul

Todos os três saídas (chaves, valores, ambos) para classificar dicionários são cobertos aqui em um estilo claro e conciso: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman A classe base pode não ter sido solicitada, mas é claro que OrderedDict .
Taylor Edmiston

1
No Python 3.6+, os dicionários preservam a ordem de inserção. Obviamente, isso não é o mesmo que a possibilidade de classificá-los por valor, mas, por outro lado, não é mais válido dizer que "a estrutura de dados do dicionário não tem ordem inerente".
Konrad Kocik 31/12/19

Respostas:


4955

Python 3.6+

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
{k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

Python mais antigo

Não é possível classificar um dicionário, apenas para obter uma representação de um dicionário que esteja classificado. Os dicionários são inerentemente sem ordem, mas outros tipos, como listas e tuplas, não são. Portanto, você precisa de um tipo de dados ordenado para representar valores classificados, que serão uma lista - provavelmente uma lista de tuplas.

Por exemplo,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_xserá uma lista de tuplas classificadas pelo segundo elemento em cada tupla. dict(sorted_x) == x.

E para aqueles que desejam classificar as chaves em vez dos valores:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

No Python3, como a descompactação não é permitida [1] , podemos usar

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])

Se você deseja a saída como um ditado, pode usar collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
para horários em diversos métodos de triagem dicionário por esquemas de valor: writeonly.wordpress.com/2008/08/30/...
Gregg Lind

164
sorted_x.reverse()vai lhe dar uma ordem descendente (pelo segundo elemento tuple)
saidimu apale

414
saidimu: Como já estamos usando sorted(), é muito mais eficiente passar no reverse=Trueargumento.
Rmh

121
Em python3 eu usei um lambda: sorted(d.items(), key=lambda x: x[1]). Isso funcionará no python 2.x?
Keyo

84
OrderedDict adicionado às coleções no 2.7. Exemplo de classificação mostrado em: docs.python.org/library/…
monkut

1264

Tão simples quanto: sorted(dict1, key=dict1.get)

Bem, é realmente possível fazer uma "classificação por valores de dicionário". Recentemente, tive que fazer isso em um Code Golf (questão de estouro de pilha : Code golf: Word chart chart ). Resumidamente, o problema era do tipo: dado um texto, conte com que frequência cada palavra é encontrada e exiba uma lista das principais palavras, ordenadas pela frequência decrescente.

Se você construir um dicionário com as palavras como chaves e o número de ocorrências de cada palavra como valor, simplifique aqui como:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
    d[w] += 1

então você pode obter uma lista das palavras, ordenadas pela frequência de uso com sorted(d, key=d.get)- a classificação itera sobre as teclas do dicionário, usando o número de ocorrências de palavras como uma chave de classificação.

for w in sorted(d, key=d.get, reverse=True):
    print(w, d[w])

Estou escrevendo esta explicação detalhada para ilustrar o que as pessoas costumam dizer com "eu posso classificar facilmente um dicionário por chave, mas como classifico por valor" - e acho que a postagem original estava tentando resolver esse problema. E a solução é fazer um tipo de lista de chaves, com base nos valores, como mostrado acima.


31
Isso também é bom, mas key=operator.itemgetter(1)deve ser mais escalável para a eficiência dekey=d.get
SMCI

3
@raylu Eu observo um comportamento "não funciona" usando o itemgetter: ----- from operator import itemgetter d = {"a":7, "b":1, "c":5, "d":3} sorted_keys = sorted(d, key=itemgetter, reverse=True) for key in sorted_keys: print "%s: %d" % (key, d[key]) ----- -> b: 1 c: 5 a: 7 d: 3 Os resultados mudam cada vez que executo o código: estranho . (desculpe, não pode obter o código para exibir corretamente)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)e for key, val in sorted_keys: print "%s: %d" % (key, val)- itemgetter cria uma função quando é chamada, você não a usa diretamente como no seu exemplo. E uma iteração simples em um dicionário usa as chaves sem os valores
Izkata

18
i ter vindo do futuro para dizer-lhe de collections.Counter, que tem um most_commonmétodo que lhe possam interessar :)
Eevee

2
@ Eevee - existe o risco de ser mal interpretado em comentários breves que não sejam da f2f. Amuzing tidbit: collections.Counterfoi adicionado no 2.7, lançado quase exatamente há 7 anos! (Eu não sabia sobre isso na época - além disso, eu o teria evitado no código-golfe com a finalidade de concisão, que é a única obsessão do jogo) #
219 Ban Ban Nas

859

Você poderia usar:

sorted(d.items(), key=lambda x: x[1])

Isso classificará o dicionário pelos valores de cada entrada do dicionário, do menor para o maior.

Para classificá-lo em ordem decrescente, basta adicionar reverse=True:

sorted(d.items(), key=lambda x: x[1], reverse=True)

Entrada:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}
a = sorted(d.items(), key=lambda x: x[1])    
print(a)

Resultado:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]

Pelo que vi ( docs.python.org/2/library/… ), há uma classe chamada OrderedDict que pode ser classificada e manter a ordem enquanto ainda é um dicionário. A partir dos exemplos de código, você pode usar lambda para classificá-lo, mas eu não tentei pessoalmente: P
UsAndRufus

53
Eu prefiro key=lambda (k, v): vpessoalmente
Claudiu

35
@ Claudiu Eu também gosto dessa (k, v)sintaxe, mas não está disponível no Python 3, onde a descompactação de parâmetros de tupla foi removida.
22816 Bob Stein

2
dict(sorted(d.items(), key=lambda x: x[1])).
Dr_Hope 16/07/19

3
Não. Criar um ditado a partir de uma lista classificada de tuplas mata a ordem novamente ...
Jean-François Fabre

233

Os ditados não podem ser classificados, mas você pode criar uma lista classificada.

Uma lista classificada de valores de dict:

sorted(d.values())

Uma lista de pares (chave, valor), classificados por valor:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))

Em que ordem são colocadas as chaves com o mesmo valor? Classifiquei a lista primeiro por chaves e depois por valores, mas a ordem das chaves com o mesmo valor não permanece.
SabreWolfy

1
Os ditados agora podem ser classificados, começando com o CPython 3.6 e todas as outras implementações em Python começando com 3.7
Boris

161

No Python 2.7 recente, temos o novo tipo OrderedDict , que lembra a ordem na qual os itens foram adicionados.

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

Para criar um novo dicionário ordenado a partir do original, classificando pelos valores:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

O OrderedDict se comporta como um ditado normal:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])

5
Não é disso que se trata a questão - não se trata de manter a ordem das chaves, mas de "classificar por valor"
Nas Banov

10
@Nas Banov: NÃO está classificando pela chave. está ordenando na ordem, criamos os itens. no nosso caso, classificamos pelo valor. infelizmente, o ditado de 3 itens foi escolhido, infelizmente, para que a ordem fosse a mesma, quando classificada por valor e chave, então ampliei o ditado de amostra.
Mykhal

sorted(d.items(), key=lambda x: x[1])Você pode explicar quais são os xmeios, por que isso pode levar x[1]ao lambda? Por que não pode ser x[0]? Muito obrigado!
JZAU

1
O @Boern d.items()retorna um contêiner de (key, value)tuplas do tipo lista . [0]acessa o primeiro elemento da tupla - a chave - e [1]acessa o segundo elemento - o valor.
precisa

2
Nota: A partir de 3,6 (como um detalhe de implementação CPython / PyPy) e como de 3,7 (como garantia linguagem Python), plain dicté a inserção ordenada, bem, então você pode simplesmente substituir OrderedDictcom dictpara o código em execução em Python moderna. OrderedDictnão é mais necessário, a menos que você precise reorganizar a ordem de um existente dict(com move_to_end/ popitem) ou precise que comparações de igualdade sejam sensíveis à ordem. Ele usa muito mais memória do que simples dict, então se você puder, dicté o caminho a percorrer.
ShadowRanger

104

ATUALIZAÇÃO: 5 DE DEZEMBRO DE 2015 usando o Python 3.5

Embora tenha achado útil a resposta aceita, também fiquei surpreso por ela não ter sido atualizada para referenciar o OrderedDict do módulo de coleções de bibliotecas padrão como uma alternativa viável e moderna - projetada para resolver exatamente esse tipo de problema.

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

A documentação oficial do OrderedDict também oferece um exemplo muito semelhante, mas usando um lambda para a função de classificação:

# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

86

Praticamente o mesmo que a resposta de Hank Gay :

sorted([(value,key) for (key,value) in mydict.items()])

Ou um pouco otimizado, como sugerido por John Fouhy:

sorted((value,key) for (key,value) in mydict.items())

9
..e como na resposta de Hank Gay, você não precisa de colchetes. Sorted () terá qualquer iterável, como uma expressão geradora.
John Fouhy

Você ainda pode precisar trocar os elementos da tupla (valor, chave) para terminar com o (chave, valor). Outra compreensão da lista é então necessária. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale

não, é melhor deixar colchetes, porque sortedprecisará reconstruir a lista de qualquer maneira, e a reconstrução do gencomp será mais rápida. Bom para codegolfing, ruim para velocidade. Mantenha a ([])versão feia .
Jean-François Fabre

75

Muitas vezes, pode ser muito útil usar o nomeado duplo . Por exemplo, você tem um dicionário de 'nome' como chaves e 'pontuação' como valores e deseja classificar em 'pontuação':

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

classificação com a menor pontuação primeiro:

worst = sorted(Player(v,k) for (k,v) in d.items())

classificação com a pontuação mais alta primeiro:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

Agora você pode obter o nome e a pontuação de, digamos, o segundo melhor jogador (índice = 1), muito pythonicamente assim:

player = best[1]
player.name
    'Richard'
player.score
    7

Como eu poderia convertê-lo novamente em um dicionário?
rowana

as_list = [Player (v, k) para (k, v) em d.items ()] as_dict = dict ((p.name, p.score) para p em as_list)
Remi

72

A partir do Python 3.6, o ditado interno será ordenado

Boas notícias, portanto, o caso de uso original do OP de pares de mapeamento recuperados de um banco de dados com IDs de string exclusivos como chaves e valores numéricos como valores em um dict interno do Python v3.6 + deve agora respeitar a ordem de inserção.

Se digamos as expressões de tabela de duas colunas resultantes de uma consulta ao banco de dados como:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

seria armazenado em duas tuplas Python, k_seq e v_seq (alinhadas pelo índice numérico e com a mesma duração, é claro), então:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

Permitir a saída mais tarde como:

for k, v in ordered_map.items():
    print(k, v)

neste caso (para o novo ditado interno do Python 3.6+!):

foo 0
bar 1
baz 42

na mesma ordem por valor de v.

Onde na instalação do Python 3.5 na minha máquina, atualmente ela produz:

bar 1
foo 0
baz 42

Detalhes:

Conforme proposto em 2012 por Raymond Hettinger (cf. mail no python-dev com o assunto "Dicionários mais compactos com iteração mais rápida" ) e agora (em 2016) anunciado em um email de Victor Stinner para python-dev com o assunto "dict Python 3.6 torna-se compactar e obter uma versão privada, e as palavras-chave serão ordenadas " devido à correção / implementação da edição 27350 " Dict compacto e ordenado " no Python 3.6, agora poderemos usar um dict interno para manter a ordem de inserção !!

Esperamos que isso leve a uma implementação de OrderedDict de camada fina como um primeiro passo. Como @ JimFasarakis-Hilliard indicou, alguns veem casos de uso para o tipo OrderedDict também no futuro. Acho que a comunidade Python em geral inspecionará cuidadosamente, se isso resistirá ao teste do tempo e quais serão os próximos passos.

Hora de repensar nossos hábitos de codificação para não perder as possibilidades abertas pela ordenação estável de:

  • Argumentos de palavras-chave e
  • armazenamento intermediário (dict)

O primeiro porque facilita o envio na implementação de funções e métodos em alguns casos.

A segunda, como incentiva a usar mais facilmente dicts como armazenamento intermediário nos pipelines de processamento.

Raymond Hettinger gentilmente forneceu a documentação que explica " Os dicionários Tech Behind Python 3.6 " - a partir de sua apresentação em San Francisco Python Meetup Group 2016-DEC-08.

E talvez algumas páginas de perguntas e respostas com alto nível de Stack Overflow recebam variantes dessas informações e muitas respostas de alta qualidade também exigirão uma atualização por versão.

Advertência Emptor (mas também veja abaixo a atualização 2017-12-15):

Como o @ajcr observa, com razão: "O aspecto de preservação de pedidos dessa nova implementação é considerado um detalhe da implementação e não deve ser considerado". (a partir do whatsnew36 ), não a escolha, mas a citação foi cortada um pouco pessimista ;-). Ele continua como "(isso pode mudar no futuro, mas é desejável ter essa nova implementação de ditado no idioma para alguns lançamentos antes de alterar a especificação do idioma para determinar a semântica de preservação de ordem para todas as implementações atuais e futuras do Python; isso também ajuda a preservar a compatibilidade com versões anteriores da linguagem em que a ordem de iteração aleatória ainda está em vigor, por exemplo, Python 3.5). "

Assim como em algumas línguas humanas (por exemplo, alemão), o uso molda a língua, e a vontade agora foi declarada ... no que é novo36 .

Atualização 15-12-2017:

Em um email para a lista python-dev , Guido van Rossum declarou:

Faça assim. "Dict mantém ordem de inserção" é a decisão. Obrigado!

Portanto, o efeito colateral do CPython da versão 3.6 do pedido de inserção de dict agora está se tornando parte da especificação da linguagem (e não mais apenas um detalhe da implementação). Esse segmento de correio também apareceu em alguns objetivos de design distintos, collections.OrderedDictconforme lembrado por Raymond Hettinger durante a discussão.


15
O aviso na página 'whatsnew' ao qual você está vinculado deve ser enfatizado: o aspecto de preservação de pedidos dessa nova implementação é considerado um detalhe da implementação e não deve ser considerado . Ninguém deve assumir que o dicttipo respeitará a ordem de inserção em seu código. Isso não faz parte da definição do idioma e a implementação pode mudar em qualquer versão futura. Continue usando OrderedDictpara garantir o pedido.
Alex Riley #

@ajcr obrigado pela ressalva, muito apreciado - como smileys e talvez foram inseridos em minha resposta, eles devem indicar que a mudança é massiva, mas é claro, disponível apenas para CPython (implementação de referência) e PyPy. Para algo completamente diferente ... Eu raramente falo com detalhes de não implementação ao codificar instruções homem-máquina. Se tivesse sido apenas Jython ;-) ... talvez eu não tivesse tido a coragem de escrever.
Diletante

OrderedDictdefinitivamente não será descartado; em vez disso, ele se tornará um invólucro fino em torno da implementação de dict atual (portanto, você pode adicionar que também se tornará mais compacto). Adicionar esse snippet à ImportErrornão é a melhor idéia, pois engana os leitores que OrderedDictnão têm utilidade.
Dimitris Fasarakis Hilliard

@ JimFasarakis-Hilliard obrigado pelo feedback. "As melhores ideias" me fizeram sorrir - o futuro geralmente é difícil de prever. Mas gosto que sua sugestão verifique as fontes, tente e atualize a resposta de acordo. Obrigado novamente.
Diletant

8
@AlexRiley Esta ressalva não é mais precisa. Python3.7 garante dicionários ordenados.
Gerrit

42

Eu tive o mesmo problema e resolvi-o assim:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(As pessoas que respondem "Não é possível classificar um ditado" não leram a pergunta! Na verdade, "Eu posso classificar as chaves, mas como classificar com base nos valores?" Significa claramente que ele deseja uma lista de as chaves classificadas de acordo com o valor de seus valores.)

Observe que a ordem não está bem definida (chaves com o mesmo valor estarão em uma ordem arbitrária na lista de saída).


1
Você está perdendo o valor do resultado
Dejell 07/01

Observe que você está iterando o dicionário e buscando valores pela chave deles, portanto, em termos de desempenho, essa não é uma solução ideal.
Ron Klein

1
@ Dejell: como o colaborador diz, ele interpreta a pergunta como "posso obter a lista de chaves classificada de acordo com os valores". Não precisamos dos valores no resultado, temos eles no dicionário.
Max

36

Se os valores são numéricos você também pode usar Countera partir de coleções .

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    

e se o dicionário for >>> x = {'olá': 1, 'python': 5, 'world': 300} '
James Sapam

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()[('world', 300), ('python', 5), ('hello', 1)]. Isso realmente funciona para qualquer tipo de valor classificável (embora muitas outras operações do contador exijam que os valores sejam comparáveis ​​aos ints).
Lvc # 28/13

34

No Python 2.7, basta:

from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

copiar e colar de: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Desfrutar ;-)


25

Este é o código:

import operator
origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

Aqui estão os resultados:

Original

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

Classificação

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}

25

Tente a seguinte abordagem. Vamos definir um dicionário chamado mydict com os seguintes dados:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

Se alguém quiser classificar o dicionário por chaves, poderá fazer algo como:

for key in sorted(mydict.iterkeys()):
    print "%s: %s" % (key, mydict[key])

Isso deve retornar a seguinte saída:

alan: 2
bob: 1
carl: 40
danny: 3

Por outro lado, se alguém quiser classificar um dicionário por valor (como é solicitado na pergunta), poderá fazer o seguinte:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

O resultado desse comando (classificando o dicionário por valor) deve retornar o seguinte:

bob: 1
alan: 2
danny: 3
carl: 40

Impressionante! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):permite classificar por uma subchave
Andomar

isso me dá erro de sintaxe perto de lambda em Python3
Suleman Elahi

21

A partir do Python 3.6, os dictobjetos agora são ordenados por ordem de inserção. Está oficialmente nas especificações do Python 3.7.

>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

Antes disso, você tinha que usar OrderedDict.

A documentação do Python 3.7 diz:

Alterado na versão 3.7: é garantido que o pedido de dicionário seja um pedido de inserção. Esse comportamento foi o detalhe de implementação do CPython da 3.6.


funciona bem! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))para DESC
vizyourdata

20

Você pode criar um "índice invertido", também

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

Agora seu inverso tem os valores; cada valor tem uma lista de chaves aplicáveis.

for k in sorted(inverse):
    print k, inverse[k]

19

Você pode usar as coleções . Observe que isso funcionará para valores numéricos e não numéricos.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

7
Como isso é diferente da resposta de Ivan Sas ?
Peter Mortensen

15

Você pode usar um skip dict, que é um dicionário classificado permanentemente por valor.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

Se você usar keys(), values()ouitems() então, iterará na ordem classificada por valor.

É implementado usando a estrutura de dados da lista de pulos.


podemos mudar a ordem de classificação, no momento, está aumentando, mas eu quero decretar.
Suleman Elahi

afaik você teria que negar seus valores para reverter a ordem
malthe

uau, eu não penso assim ... obrigado.
Suleman Elahi

14

Você também pode usar a função personalizada que pode ser passada para a chave.

def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)

12
from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict

2
pergunta era: classificar por valor, não por chaves ... eu gosto de ver uma função. Você pode importar coleções e de uso claro classificadas (data.values ())
Remi

10

Conforme apontado por Dilettant , o Python 3.6 agora manterá a ordem ! Eu pensei em compartilhar uma função que escrevi que facilita a classificação de um iterável (tupla, lista, ditado). No último caso, você pode classificar chaves ou valores e levar em consideração a comparação numérica.Somente para> = 3.6!

Quando você tenta usar classificados em um iterável que contém, por exemplo, seqüências de caracteres e ints, o sortido () falhará. Claro que você pode forçar a comparação de strings com str (). No entanto, em alguns casos, você deseja fazer uma comparação numérica real em que 12seja menor que 20(o que não é o caso na comparação de cadeias). Então, eu vim com o seguinte. Quando você deseja uma comparação numérica explícita, pode usar o sinalizador num_as_numque tentará fazer a classificação numérica explícita, tentando converter todos os valores em flutuantes. Se for bem-sucedido, ele fará a classificação numérica, caso contrário, recorrerá à comparação de cadeias.

Comentários para melhorias ou solicitações push são bem-vindos.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))

      return _sorted

    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")

9

Aqui está uma solução usando o zip on d.values()ed.keys() . Algumas linhas abaixo deste link (nos objetos de exibição Dicionário) são:

Isso permite a criação de pares (valor, chave) usando zip (): pairs = zip (d.values ​​(), d.keys ()).

Para que possamos fazer o seguinte:

d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(zip(d.values(), d.keys()))

print d_sorted 
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]

9

Claro, lembre-se, você precisa usar OrderedDictporque os dicionários regulares do Python não mantêm a ordem original.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))

Se você não possui o Python 2.7 ou superior, o melhor que você pode fazer é iterar sobre os valores em uma função de gerador. (Existe um OrderedDictpara 2.4 e 2.6 aqui , mas

a) Não sei como funciona

e

b) Você tem que baixar e instalar, é claro. Se você não tiver acesso administrativo, receio que a opção esteja desativada.)


def gen(originalDict):
    for x, y in sorted(zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

Você também pode imprimir todos os valores

for bleh, meh in gen(myDict):
    print(bleh, meh)

Lembre-se de remover os parênteses após a impressão, se não estiver usando o Python 3.0 ou superior


dicionários regulares de Python não mantêm a ordem original - como no Python 3.7, eles mantêm .
gerrit

7

Use ValueSortedDict de dicts :

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

6

Isso funciona no 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)

6

Acabei de aprender habilidades relevantes do Python para todos .

Você pode usar uma lista temporária para ajudá-lo a classificar o dicionário:

#Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# create a temporary list
tmp = []

# iterate through the dictionary and append each tuple into the temporary list 
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

Se você deseja classificar a lista em ordem decrescente, basta alterar a linha de classificação original para:

tmp = sorted(tmp, reverse=True)

Usando a compreensão da lista, o liner seria:

#Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
#One liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
#One liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

Saída de amostra:

#Asending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
#Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]

isso é ordenar por chaves, não por valores.
Rubel

Se você quiser imprimi-lo no formato inicial, faça: print ([(k, v) para v, k classificado ([(v, k) para k, v nos itens d (itens)))]. A saída é: [('laranja', 1.0), ('maçã', 500.1), ('abacaxi', 789.0), ('banana', 1500.2)]. Com [(k, v) para v, k em ordenado ([(v, k) para k, v em d.items ()], reverse = True)] a saída é: [('banana', 1500.2), ('abacaxi', 789,0), ('maçã', 500,1), ('laranja', 1,0)]
Hermes Morales

5

Itere através de um ditado e classifique-o por seus valores em ordem decrescente:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

5

Se seus valores forem inteiros e você usar o Python 2.7 ou mais recente, poderá usar em collections.Countervez de dict. O most_commonmétodo fornecerá todos os itens, classificados pelo valor.


5

Por uma questão de integridade, estou postando uma solução usando heapq . Observe que esse método funcionará para valores numéricos e não numéricos

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

4

Devido aos requisitos para manter a compatibilidade com versões anteriores do Python , acho que a solução OrderedDict é muito imprudente. Você quer algo que funcione com o Python 2.7 e versões anteriores.

Mas a solução de coleções mencionada em outra resposta é absolutamente excelente, porque você treina novamente uma conexão entre a chave e o valor que, no caso dos dicionários, é extremamente importante.

Não concordo com a opção número um apresentada em outra resposta, porque joga fora as chaves.

Usei a solução mencionada acima (código mostrado abaixo) e retive o acesso às chaves e aos valores e, no meu caso, a ordem estava nos valores, mas a importância era a ordem das chaves após a ordem dos valores.

from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.