Come ordinare un dizionario per valore?


3422

Ho un dizionario di valori letti da due campi in un database: un campo stringa e un campo numerico. Il campo stringa è unico, quindi questa è la chiave del dizionario.

Posso ordinare in base alle chiavi, ma come posso ordinare in base ai valori?

Nota: ho letto la domanda Stack Overflow qui Come ordinare un elenco di dizionari in base al valore del dizionario? e probabilmente potrei cambiare il mio codice per avere un elenco di dizionari, ma poiché non ho davvero bisogno di un elenco di dizionari, volevo sapere se esiste una soluzione più semplice per ordinare in ordine crescente o decrescente.


9
La struttura dei dati del dizionario non ha un ordine intrinseco. Puoi iterarlo, ma non c'è nulla che garantisca che l'iterazione seguirà un ordine particolare. Questo è in base alla progettazione, quindi la tua scommessa migliore è quella di usare una struttura di dati anohter per la rappresentazione.
Daishiman,

135
"sort ()" può operare sui dizionari (e restituisce un elenco di chiavi ordinate), quindi penso che ne sia consapevole. Senza conoscere il suo programma, è assurdo dire a qualcuno che sta usando la struttura dei dati sbagliata. Se le ricerche veloci sono ciò di cui hai bisogno il 90% delle volte, allora un dict è probabilmente quello che vuoi.
bobpaul,

Tutte e tre le uscite (chiavi, valori, entrambi) per l'ordinamento dizionari sono coperti qui in uno stile chiaro e conciso: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman La classe base potrebbe non essere ordinata, ma OrderedDict è ovviamente.
Taylor Edmiston,

1
In Python 3.6+ i dizionari mantengono l'ordine di inserimento. Ciò ovviamente non equivale alla possibilità di ordinarli per valore, ma d'altra parte non è più valido affermare che "la struttura dei dati del dizionario non ha un ordine intrinseco".
Konrad Kocik,

Risposte:


4956

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 precedente

Non è possibile ordinare un dizionario, solo per ottenere una rappresentazione di un dizionario ordinato. I dizionari sono intrinsecamente privi di ordine, ma altri tipi, come elenchi e tuple, non lo sono. Quindi è necessario un tipo di dati ordinato per rappresentare i valori ordinati, che sarà un elenco, probabilmente un elenco di tuple.

Per esempio,

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

sorted_xsarà un elenco di tuple ordinate per secondo elemento in ciascuna tupla. dict(sorted_x) == x.

E per coloro che desiderano ordinare le chiavi anziché i valori:

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

In Python3 poiché il disimballaggio non è consentito [1] che possiamo usare

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

Se vuoi l'output come dict, puoi usare collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
per i tempi su vari ordinamenti di dizionari per schemi di valore: writeonly.wordpress.com/2008/08/30/…
Gregg Lind

164
sorted_x.reverse()ti darà un ordine decrescente (dal secondo elemento tupla)
saidimu apale

414
saidimu: Dal momento che stiamo già utilizzando sorted(), è molto più efficiente passare l' reverse=Trueargomento.
rmh

121
In python3 ho usato un lambda: sorted(d.items(), key=lambda x: x[1]). Funzionerà in Python 2.x?
Keyo,

84
OrderedDict aggiunto alle raccolte in 2.7. Esempio di ordinamento mostrato su: docs.python.org/library/…
monkut

1264

Semplice come: sorted(dict1, key=dict1.get)

Bene, in realtà è possibile fare un "ordinamento per valori di dizionario". Recentemente ho dovuto farlo in un Code Golf (Stack Overflow domanda Code golf: grafico della frequenza delle parole ). Abbreviato, il problema era del tipo: dato un testo, conta la frequenza con cui ogni parola viene incontrata e visualizza un elenco delle parole migliori, ordinate per frequenza decrescente.

Se costruisci un dizionario con le parole come chiavi e il numero di occorrenze di ogni parola come valore, qui semplificato come:

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

quindi puoi ottenere un elenco delle parole, ordinate per frequenza d'uso con sorted(d, key=d.get)- l'ordinamento scorre le chiavi del dizionario, usando il numero di occorrenze di parole come chiave di ordinamento.

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

Sto scrivendo questa spiegazione dettagliata per illustrare cosa spesso la gente intende per "Posso facilmente ordinare un dizionario per chiave, ma come faccio a ordinare in base al valore" - e penso che il post originale stesse cercando di risolvere un problema del genere. E la soluzione è fare una sorta di elenco delle chiavi, in base ai valori, come mostrato sopra.


32
Anche questo è buono ma key=operator.itemgetter(1)dovrebbe essere più scalabile per efficienza rispetto akey=d.get
smci

3
@raylu Osservo un comportamento "non funziona" usando 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 I risultati cambiano ogni volta che eseguo il codice: strano . (scusate, non riesco a visualizzare correttamente il codice)
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 crea una funzione quando viene chiamata, non la usi direttamente come nel tuo esempio. E una semplice iterazione su un dict usa le chiavi senza i valori
Izkata,

18
vengo dal futuro per dirtelo collections.Counter, che ha un most_commonmetodo che potrebbe interessarti :)
Eevee,

2
@Eevee - c'è questo, il rischio di essere fraintesi in brevi commenti non f2f. Amuzing tidbit: è collections.Counterstato aggiunto in 2.7, che è stato rilasciato quasi esattamente 7 anni fa! (Allora non lo sapevo - inoltre lo avrei evitato nel code-golf ai fini della brevità, che è l'unica ossessione del gioco)
Nas Banov,

859

Puoi usare:

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

Questo ordinerà il dizionario in base ai valori di ciascuna voce all'interno del dizionario dal più piccolo al più grande.

Per ordinarlo in ordine decrescente basta aggiungere reverse=True:

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

Ingresso:

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

Produzione:

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

Da quello che ho visto ( docs.python.org/2/library/… ), esiste una classe chiamata OrderedDict che può essere ordinata e conservare l'ordine pur rimanendo un dizionario. Dagli esempi di codice, puoi usare lambda per ordinarlo, ma non l'ho provato personalmente: P
UsAndRufus

53
Preferirei key=lambda (k, v): vpersonalmente
Claudiu il

35
@Claudiu Mi piace anche quella (k, v)sintassi, ma non è disponibile in Python 3 dove è stato rimosso il disimballaggio dei parametri di tupla .
Bob Stein,

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

3
No. La creazione di un dict da un elenco ordinato di tuple uccide di nuovo l'ordine ...
Jean-François Fabre

233

I Dicts non possono essere ordinati, ma è possibile creare un elenco ordinato da essi.

Un elenco ordinato di valori di dict:

sorted(d.values())

Un elenco di coppie (chiave, valore), ordinate per valore:

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

In quale ordine vengono posizionate le chiavi con lo stesso valore? Prima ho ordinato l'elenco per chiavi, poi per valori, ma l'ordine delle chiavi con lo stesso valore non rimane.
SabreWolfy,

1
Ora i Dicts possono essere ordinati, iniziando con CPython 3.6 e tutte le altre implementazioni di Python che iniziano con 3.7
Boris

161

In Python 2.7 recente, abbiamo il nuovo tipo OrderedDict , che ricorda l'ordine in cui gli elementi sono stati aggiunti.

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

Per creare un nuovo dizionario ordinato dall'originale, ordinandolo in base ai valori:

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

OrderedDict si comporta come un normale dict:

>>> 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
Non si tratta della domanda: non si tratta di mantenere l'ordine delle chiavi ma di "ordinare per valore"
Nas Banov,

10
@Nas Banov: NON sta ordinando per chiave. sta ordinando nell'ordine, creiamo gli articoli. nel nostro caso, ordiniamo per valore. sfortunatamente, il dict di 3 elementi è stato purtroppo scelto quindi l'ordine era lo stesso, quando ordinato voth per valore e chiave, quindi ho ampliato il dict di esempio.
mykhal,

sorted(d.items(), key=lambda x: x[1])Puoi spiegarci cosa xsignifica, perché può volerci x[1]lambda? Perché non può essere x[0]? Grazie mille!
JZAU

1
@Boern d.items()restituisce un contenitore simile a una lista di (key, value)tuple. [0]accede al primo elemento della tupla - la chiave - e [1]accede al secondo elemento - il valore.
BallpointBen,

2
Nota: A partire da 3.6 (come dettaglio di implementazione di CPython / PyPy) e da 3.7 (come garanzia di linguaggio Python), anche il semplice dictordine di inserimento è ordinato, quindi puoi semplicemente sostituirlo OrderedDictcon dictper il codice in esecuzione su Python moderno. OrderedDictnon è più necessario a meno che non sia necessario riorganizzare l'ordine di un esistente dict(con move_to_end/ popitem) o non siano necessari confronti di uguaglianza per essere sensibili all'ordine. Usa molta più memoria del semplice dict, quindi se puoi, dictè la strada da percorrere.
ShadowRanger

104

AGGIORNAMENTO: 5 DICEMBRE 2015 utilizzando Python 3.5

Mentre ho trovato utile la risposta accettata, sono rimasto sorpreso anche dal fatto che non sia stato aggiornato per fare riferimento a OrderedDict dal modulo delle raccolte di librerie standard come alternativa valida e moderna, progettata per risolvere esattamente questo tipo di 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)])

La documentazione ufficiale di OrderedDict offre anche un esempio molto simile, ma usando un lambda per la funzione di ordinamento:

# 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 uguale alla risposta di Hank Gay :

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

O leggermente ottimizzato come suggerito da John Fouhy:

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

9
..e come nella risposta di Hank Gay, non hai bisogno delle parentesi quadre. sort () prenderà felicemente qualsiasi iterabile, come un'espressione del generatore.
John Fouhy,

Potrebbe essere necessario scambiare gli elementi tupla (valore, chiave) per finire con (chiave, valore). È quindi necessaria un'altra comprensione dell'elenco. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale,

no, è meglio lasciare parentesi quadre, perché sorteddovrà comunque ricostruire la lista, e la ricostruzione da gencomp sarà più veloce. Buono per codegolfing, cattivo per la velocità. Mantieni la brutta ([])versione.
Jean-François Fabre

75

Spesso può essere molto utile usare namedtuple . Ad esempio, hai un dizionario di "nome" come chiavi e "punteggio" come valori e vuoi ordinare su "punteggio":

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

prima l'ordinamento con il punteggio più basso:

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

prima l'ordinamento con il punteggio più alto:

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

Ora puoi ottenere il nome e il punteggio di, diciamo che il secondo miglior giocatore (indice = 1) in questo modo molto pitonicamente:

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

Come potrei riconvertirlo in un dizionario?
Rowana,

as_list = [Giocatore (v, k) per (k, v) in d.items ()] as_dict = dict ((p.name, p.score) per p in as_list)
Remi

72

A partire da Python 3.6 verrà ordinato il dict incorporato

Buone notizie, quindi il caso d'uso originale dell'OP di coppie di mapping recuperate da un database con ID stringa univoci come chiavi e valori numerici come valori in un dict Python v3.6 + integrato, dovrebbe ora rispettare l'ordine di inserimento.

Se dico le risultanti espressioni della tabella di due colonne da una query del database come:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

verrebbe memorizzato in due tuple Python, k_seq e v_seq (allineati per indice numerico e con la stessa lunghezza del corso), quindi:

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

Consentire l'output in seguito come:

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

cedendo in questo caso (per il nuovo dict incorporato di Python 3.6+!):

foo 0
bar 1
baz 42

nello stesso ordine per valore di v.

Dove nell'installazione di Python 3.5 sulla mia macchina attualmente produce:

bar 1
foo 0
baz 42

Dettagli:

Come proposto nel 2012 da Raymond Hettinger (cfr. Mail su Python-dev con soggetto "Dizionari più compatti con iterazione più veloce" ) e ora (nel 2016) annunciato in una mail di Victor Stinner a python-dev con soggetto "Python 3.6 dict diventa compatta e ottiene una versione privata e le parole chiave vengono ordinate "a causa della correzione / implementazione del problema 27350 " Compatto e ordinato " in Python 3.6 ora saremo in grado di usare un dict incorporato per mantenere l'ordine di inserimento !!

Speriamo che questo porti a un'implementazione di OrderedDict a livello sottile come primo passo. Come indicato da @ JimFasarakis-Hilliard, alcuni vedranno casi d'uso per il tipo OrderedDict anche in futuro. Penso che la comunità di Python in generale esaminerà attentamente, se questo resisterà alla prova del tempo e quali saranno i prossimi passi.

È tempo di ripensare le nostre abitudini di codifica per non perdere le possibilità aperte da un ordinamento stabile di:

  • Argomenti di parole chiave e
  • archiviazione (intermedia) di dict

Il primo perché facilita l'invio nell'implementazione di funzioni e metodi in alcuni casi.

Il secondo, in quanto incoraggia a utilizzare più facilmente dicts come memoria intermedia nelle condotte di elaborazione.

Raymond Hettinger ha gentilmente fornito la documentazione che spiega " The Tech Behind Python 3.6 Dictionaries " - dalla sua presentazione del gruppo Meetup di San Francisco Python 2016-DEC-08.

E forse alcune pagine di domande e risposte decorate con Stack Overflow riceveranno varianti di queste informazioni e molte risposte di alta qualità richiedono anche un aggiornamento per versione.

Caveat Emptor (ma vedi anche sotto aggiornamento 2017-12-15):

Come giustamente osserva @ajcr: "L'aspetto che preserva l'ordine di questa nuova implementazione è considerato un dettaglio dell'implementazione e non dovrebbe essere invocato". (dal whatsnew36 ) non nit picking, ma la citazione è stata un po 'pessimistica ;-). Continua come "(questo potrebbe cambiare in futuro, ma si desidera avere questa nuova implementazione di dict nella lingua per alcune versioni prima di cambiare le specifiche della lingua per imporre la semantica di conservazione dell'ordine per tutte le implementazioni Python attuali e future; anche questo aiuta a preservare la retrocompatibilità con le versioni precedenti del linguaggio in cui l'ordine di iterazione casuale è ancora in vigore, ad esempio Python 3.5). "

Così come in alcune lingue umane (ad esempio il tedesco), l'uso modella la lingua e la volontà è stata dichiarata ... in whatsnew36 .

Aggiornamento 15-12-2017:

In una mail all'elenco python-dev , Guido van Rossum dichiarò:

Rendilo così. "Dict mantiene l'ordine di inserimento" è la sentenza. Grazie!

Quindi, l'effetto collaterale CPython versione 3.6 dell'ordine di inserimento di dict ora sta diventando parte delle specifiche del linguaggio (e non più solo un dettaglio di implementazione). Quel thread di posta emerse anche alcuni obiettivi di progettazione distintivi per collections.OrderedDictcome ricordato da Raymond Hettinger durante la discussione.


15
L'avvertimento sulla pagina "whatsnew" a cui ti sei collegato dovrebbe essere enfatizzato: l'aspetto che preserva l'ordine di questa nuova implementazione è considerato un dettaglio dell'implementazione e non dovrebbe essere invocato . Nessuno dovrebbe supporre che il dicttipo rispetterà l'ordine di inserimento nel proprio codice. Questo non fa parte della definizione della lingua e l'implementazione potrebbe cambiare in qualsiasi versione futura. Continua a utilizzare OrderedDictper garantire l'ordine.
Alex Riley,

@ajcr grazie per l'avvertimento, molto apprezzato - dato che le faccine e forse sono state intrecciate nella mia risposta, questo dovrebbe indicare, il cambiamento è enorme ma ovviamente disponibile solo per CPython (implementazione di riferimento) e PyPy. Per qualcosa di completamente diverso ... Raramente parlo con dettagli di non implementazione durante la codifica delle istruzioni man-machine. Se solo fosse stato Jython ;-) ... forse non avrei avuto il coraggio di scriverlo.
Dilettante

OrderedDictsicuramente non verrà abbandonato; invece, diventerà un involucro sottile attorno all'attuale implementazione di dict (quindi potresti aggiungere che diventerà anche più compatto). L'aggiunta di quel frammento con il ImportErrornon è proprio la migliore idea a causa dei lettori fuorvianti che OrderedDictnon servono.
Dimitris Fasarakis Hilliard,

@ JimFasarakis-Hilliard grazie per il feedback. Le "migliori idee" mi hanno fatto sorridere - il futuro è spesso difficile da prevedere. Ma mi piace che il tuo suggerimento verifichi le fonti, lo provi e quindi aggiorni la risposta di conseguenza. Grazie ancora.
Dilettant,

8
@AlexRiley Questo avvertimento non è più preciso. Python3.7 garantisce dizionari ordinati.
Gerrit,

42

Ho avuto lo stesso problema e l'ho risolto in questo modo:

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

(Le persone che rispondono "Non è possibile ordinare un dict" non hanno letto la domanda! In effetti, "Posso ordinare le chiavi, ma come posso ordinare in base ai valori?" Significa chiaramente che desidera un elenco di le chiavi ordinate in base al valore dei loro valori.)

Si noti che l'ordine non è ben definito (le chiavi con lo stesso valore saranno in un ordine arbitrario nell'elenco di output).


1
Manca il valore del risultato
Dejell

Nota che stai iterando il dizionario e recuperando i valori in base alla loro chiave, quindi per quanto riguarda le prestazioni questa non è una soluzione ottimale.
Ron Klein,

1
@Dejell: come dice il collaboratore, interpreta la domanda come "posso ottenere l'elenco delle chiavi ordinate in base ai valori". Non abbiamo bisogno dei valori nel risultato, li abbiamo nel dizionario.
Max

36

Se i valori sono numerici, è possibile utilizzare anche Counterdalle raccolte .

from collections import Counter

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

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

che dire se il tuo dizionario è >>> x = {'hello': 1, 'python': 5, 'world': 300}
James Sapam,

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()[('world', 300), ('python', 5), ('hello', 1)]. Questo funziona effettivamente per qualsiasi tipo di valore ordinabile (sebbene molte altre operazioni Counter richiedano che i valori siano comparabili agli ints).
PVC,

34

In Python 2.7, fai semplicemente:

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

copia-incolla da: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Godere ;-)


25

Questo è il codice:

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

Ecco i risultati:

Originale

{'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}

Rango

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

Prova il seguente approccio. Definiamo un dizionario chiamato mydict con i seguenti dati:

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

Se si volesse ordinare il dizionario in base alle chiavi, si potrebbe fare qualcosa del tipo:

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

Questo dovrebbe restituire il seguente output:

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

D'altra parte, se si volesse ordinare un dizionario per valore (come richiesto nella domanda), si potrebbe fare quanto segue:

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

Il risultato di questo comando (ordinamento del dizionario per valore) dovrebbe restituire quanto segue:

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

Eccezionale! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):ti permette di ordinare in base a una sottochiave
Andomar

mi dà un errore di sintassi vicino lambda in Python3
Suleman Elahi il

21

A partire da Python 3.6, gli dictoggetti sono ora ordinati in base all'ordine di inserimento. È ufficialmente nelle specifiche di 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}

Prima di allora, dovevi usare OrderedDict .

La documentazione di Python 3.7 dice:

Modificato nella versione 3.7: l'ordine del dizionario è garantito come ordine di inserimento. Questo comportamento era il dettaglio dell'implementazione di CPython dalla 3.6.


funziona alla grande! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))per DESC
vizyourdata,

20

Puoi anche creare un "indice invertito"

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

Ora il tuo inverso ha i valori; ogni valore ha un elenco di chiavi applicabili.

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

19

Puoi usare le collezioni . Contatore . Nota, questo funzionerà con valori sia numerici che non numerici.

>>> 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
In che cosa differisce dalla risposta di Ivan Sas ?
Peter Mortensen,

15

È possibile utilizzare un skip dict che è un dizionario ordinato in modo permanente per valore.

>>> 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 si utilizza keys(), values()o items()Allora ti iterazioni in modo ordinato per valore.

È implementato utilizzando la struttura dati dell'elenco skip .


possiamo cambiare l'ordine di ordinamento, in questo momento, è crescente, ma voglio declinare.
Suleman Elahi,

dopo, dovresti negare i tuoi valori per invertire l'ordine
malthe

caspita, non la penso così ... grazie.
Suleman Elahi,

14

È inoltre possibile utilizzare la funzione personalizzata che può essere passata al tasto.

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
la domanda era: ordina per valore, non per chiavi ... Mi piace vedere una funzione. Puoi importare raccolte e, naturalmente, utilizzare ordinato (data.values ​​())
Remi

10

Come sottolineato da Dilettant , Python 3.6 ora manterrà l'ordine ! Ho pensato di condividere una funzione che ho scritto che facilita l'ordinamento di un iterabile (tupla, elenco, dict). In quest'ultimo caso, è possibile ordinare in base a chiavi o valori e può tenere conto del confronto numerico. Solo per> = 3.6!

Quando si tenta di utilizzare l'ordinamento su un iterabile che contiene ad esempio stringhe e ints, ordinato () non riuscirà. Ovviamente puoi forzare il confronto delle stringhe con str (). Tuttavia, in alcuni casi si desidera eseguire un confronto numerico effettivo dove 12è minore di 20(che non è il caso nel confronto di stringhe). Quindi ho pensato a quanto segue. Quando vuoi un confronto numerico esplicito puoi usare il flagnum_as_num che tenterà di eseguire l'ordinamento numerico esplicito tentando di convertire tutti i valori in float. Se ciò ha esito positivo, eseguirà l'ordinamento numerico, altrimenti ricorrerà al confronto delle stringhe.

Commenti di miglioramento o richieste push benvenuti.

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

Ecco una soluzione che utilizza zip on d.values()ed.keys() . Alcune righe lungo questo collegamento (sugli oggetti della vista Dizionario) sono:

Ciò consente la creazione di coppie (valore, chiave) utilizzando zip (): coppie = zip (d.values ​​(), d.keys ()).

Quindi possiamo fare quanto segue:

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

Naturalmente, ricorda, devi usarlo OrderedDictperché i normali dizionari Python non mantengono l'ordine originale.

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

Se non hai Python 2.7 o versioni successive, la cosa migliore che puoi fare è scorrere i valori in una funzione del generatore. (C'è un OrderedDictper 2.4 e 2.6 qui , ma

a) Non so quanto funzioni bene

e

b) Devi scaricarlo e installarlo ovviamente. Se non si dispone dell'accesso amministrativo, temo che l'opzione non sia disponibile.)


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

Puoi anche stampare ogni valore

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

Ricordarsi di rimuovere le parentesi dopo la stampa se non si utilizza Python 3.0 o versioni successive


i dizionari Python regolari non mantengono l'ordine originale - come in Python 3.7, lo fanno.
Gerrit,

7

Usa ValueSortedDict da 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

Funziona in 3.1.x:

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

6

Ho appena imparato le abilità pertinenti da Python per tutti .

Puoi utilizzare un elenco temporaneo per aiutarti a ordinare il dizionario:

#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 si desidera ordinare l'elenco in ordine decrescente, modificare semplicemente la riga di ordinamento originale in:

tmp = sorted(tmp, reverse=True)

Usando la comprensione dell'elenco, l'unica riga sarebbe:

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

Uscita campione:

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

questo è l'ordinamento per chiavi, non per valori.
Rubel

Se si desidera stamparlo nel formato iniziale, è necessario: print ([(k, v) per v, k in ordine ([(v, k) per k, v in d.items ()])]). L'output è: [('orange', 1.0), ('apple', 500.1), ('pineapple', 789.0), ('banana', 1500.2)]. Con [(k, v) per v, k in ordine ([(v, k) per k, v in d.items ()], reverse = True)] l'output è: [('banana', 1500.2), ('pineapple', 789.0), ('apple', 500.1), ('orange', 1.0)]
Hermes Morales

5

Scorrere un dict e ordinarlo in base ai suoi valori in ordine 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 i tuoi valori sono numeri interi e usi Python 2.7 o versioni successive, puoi utilizzare collections.Counterinvece di dict. Il most_commonmetodo ti darà tutti gli articoli, ordinati per valore.


5

Per completezza, sto pubblicando una soluzione usando heapq . Nota, questo metodo funzionerà con valori sia numerici che non numerici

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

A causa dei requisiti per mantenere la compatibilità con le versioni precedenti di Python penso che la soluzione OrderedDict sia poco saggia. Volete qualcosa che funzioni con Python 2.7 e versioni precedenti.

Ma la soluzione per le collezioni menzionata in un'altra risposta è assolutamente superba, perché riqualifichi una connessione tra chiave e valore che nel caso dei dizionari è estremamente importante.

Non sono d'accordo con la scelta numero uno presentata in un'altra risposta, perché getta via le chiavi.

Ho usato la soluzione sopra menzionata (codice mostrato sotto) e ho mantenuto l'accesso sia alle chiavi che ai valori e nel mio caso l'ordinamento era sui valori, ma l'importanza era l'ordinamento delle chiavi dopo aver ordinato i valori.

from collections import Counter

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


>> [('python', 5), ('world', 3), ('hello', 1)]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.