Domanda Come si ordina un dizionario in base al valore?


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 i tasti, ma come posso ordinare in base ai valori?

Nota: ho letto la domanda Stack Overflow Come faccio a ordinare una lista di dizionari in base ai valori del dizionario in Python? e probabilmente potrebbe 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.


2931
2018-03-05 00:49


origine


risposte:


Non è possibile ordinare un dizionario, solo per ottenere una rappresentazione di un dizionario che è 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_x sarà una lista di tuple ordinate dal secondo elemento in ciascuna tupla. dict(sorted_x) == x.

E per coloro che desiderano ordinare le chiavi al posto dei 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é la decompressione non è consentita [1] possiamo usare

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

3544
2018-03-05 00:59



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 question Code golf: tabella di frequenza di Word). Ridotto, il problema era del tipo: dato un testo, conta quante volte ogni parola viene incontrata e mostra 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 è possibile ottenere un elenco delle parole, ordinate per frequenza di utilizzo con sorted(d, key=d.get) - l'ordinamento esegue iterazioni sulle chiavi del dizionario, utilizzando 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 ciò che le persone spesso intendono con "Posso facilmente ordinare un dizionario per chiave, ma come faccio a ordinare per valore" - e penso che l'OP stia cercando di risolvere un problema del genere. E la soluzione è fare una sorta di elenco delle chiavi, in base ai valori, come mostrato sopra.


967
2017-07-05 08:01



Potresti usare:

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

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


601
2018-02-13 16:33



I dadi non possono essere ordinati, ma è possibile creare un elenco ordinato da loro.

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

165
2018-03-05 01:05



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

>>> 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, ordinando 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 dettato:

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

127
2017-07-05 02:50



AGGIORNAMENTO: 5 DICEMBRE 2015 utilizzando Python 3.5

Mentre ho trovato la risposta accettata utile, sono stato anche sorpreso che non è stato aggiornato per fare riferimento OrderedDict dalla libreria standard collezioni modulo come alternativa valida e moderna - progettato 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)])

L'ufficiale OrderedDict la documentazione offre anche un esempio molto simile, ma usando un lambda per la funzione sort:

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

75
2017-12-05 09:46



Spesso può essere molto utile da 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}

ordinamento con il punteggio più basso prima:

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

ordinamento con il punteggio più alto prima:

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

Ora puoi ottenere il nome e il punteggio di, diciamo il secondo miglior giocatore (indice = 1) molto Pythonico come questo:

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

64
2017-08-30 00:30



Praticamente uguale alla risposta di Hank Gay;


    ordinato ([(valore, chiave) per (chiave, valore) in mydict.items ()])

O ottimizzato un po 'come suggerito da John Fouhy;


    ordinato ((valore, chiave) per (chiave, valore) in mydict.items ())


57
2018-03-05 01:06



Come di Python 3.6 sarà ordinato il dict incorporato

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

Se si dice che le due espressioni di tabella a colonne risultanti da una query di database come:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

verrebbero memorizzati in due tuple Python, k_seq e v_seq (allineati per indice numerico e con la stessa lunghezza ovviamente), quindi:

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

Consentire di produrre in seguito come:

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

cedendo in questo caso (per il nuovo dict core 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 oggetto "Dizionari più compatti con iterazione più veloce") e ora (nel 2016) annunciato per posta da Victor Stinner a python-dev con soggetto "Python 3.6 dict diventa compatto e ottiene una versione privata e le parole chiave diventano ordinate" a causa della correzione / implementazione del problema 27350 "Dotto compatto e ordinato" in Python 3.6 saremo ora in grado, di usare un comando dict incorporato per mantenere l'ordine dell'inserto !!

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

È tempo di ripensare alle nostre abitudini di codifica per non perdere le possibilità aperte dall'ordinamento stabile di:

  • Argomenti della parola chiave e
  • (intermedio) immagazzinamento dict

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

Il secondo in quanto incoraggia a usare più facilmente dicts come deposito intermedio nelle pipeline di elaborazione.

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

E forse alcune pagine di domande e risposte ad alto grado di overflow impilate riceveranno varianti di queste informazioni e molte risposte di alta qualità richiederanno anche un aggiornamento per versione.

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

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

Quindi, come in alcune lingue umane (ad esempio in tedesco), l'utilizzo dà forma alla lingua e la volontà ora è stata dichiarata ... in whatsnew36.

Aggiornamento 2017-12-15:

In un posta alla lista python-dev, Guido van Rossum ha dichiarato:

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

Quindi, l'effetto collaterale CPython versione 3.6 dell'ordinamento di inserimento dict sta diventando parte delle specifiche del linguaggio (e non più solo un dettaglio di implementazione). Quel thread di posta elettronica emerso anche alcuni obiettivi di design distintivo per collections.OrderedDict come ricorda Raymond Hettinger durante la discussione.


48
2017-09-10 10:05



Dizionario fornito

e = {1:39, 4:34, 7:110, 2:87}

Ordinamento

sred = sorted(e.items(), key=lambda value: value[1])

Risultato

[(4, 34), (1, 39), (2, 87), (7, 110)]

È possibile utilizzare una funzione lambda per ordinare le voci in base al valore e archiviarle elaborate all'interno di una variabile, in questo caso Sred con e il dizionario originale

Spero possa aiutare!


41
2018-01-25 14:54