salvare - sorted python




Come si ordina un dizionario in base al valore? (20)

A partire da Python 3.6 verrà 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 "Altri dizionari compatti con iterazione più veloce" ) e ora (nel 2016) annunciato in una mail da Victor Stinner a python-dev con oggetto "Python 3.6 dict diventa compatta e ottiene una versione privata e le parole chiave diventano ordinate "a causa della correzione / implementazione del problema 27350 " Compatto e ordinato dettato " in Python 3.6 saremo ora in grado, di usare un comando automatico 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 utilizzare più facilmente dict s come memoria intermedia nelle pipeline di elaborazione.

Raymond Hettinger gentilmente ha fornito la documentazione che spiega " The Tech Behind Python 3.6 Dizionari " - 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." (da whatsnew36 ) non nit picking, ma la citazione è stata tagliata 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 il tedesco), l'uso dà forma alla lingua e la volontà ora è stata dichiarata ... in whatsnew36 .

Aggiornamento 2017-12-15:

In una mail alla lista python-dev , Guido van Rossum dichiarò:

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 le collections.OrderedDict come ricordato da Raymond Hettinger durante la discussione.

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 Stack Overflow question 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.


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 ( question Code golf: Word frequency chart ). 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 itera 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.


Ecco una soluzione che utilizza zip su d.values() e d.keys() . Alcune linee in basso su questo collegamento (su Oggetti vista dizionario) sono:

Ciò consente la creazione di coppie (valore, chiave) usando zip (): pairs = 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')]

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 dettato" non hanno letto la domanda! Infatti, "Posso ordinare i tasti, ma come posso ordinare in base ai valori?" Significa chiaramente che vuole 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 si troveranno in un ordine arbitrario nella lista di output).


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


Naturalmente, ricorda, devi usare OrderedDict perché 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, il meglio che puoi fare è iterare sui valori in una funzione generatore. (C'è un OrderedDict per 2.4 e 2.6 here , ma

a) I don't know about how well it works 

e

b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)
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 successivo


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 dal momento che 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])

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.


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 per chiavi, si potrebbe fare qualcosa come:

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

Questo dovrebbe restituire il seguente risultato:

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

D'altra parte, se si volesse ordinare un dizionario per valore (come viene chiesto 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 (ordinando il dizionario per valore) dovrebbe restituire quanto segue:

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

Puoi anche creare un "indice invertito"

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

Ora la tua inversa ha i valori; ogni valore ha un elenco di chiavi applicabili.

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

Puoi usare skip dict che è un dizionario che è ordinato per valore in modo permanente.

>>> 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 usano keys() , values() o items() allora si itererà in ordine per valore.

È implementato utilizzando la struttura dei dati di skip list .


Puoi usare la funzione ordinata di Python

sorted(iterable[, cmp[, key[, reverse]]])

Quindi puoi usare:

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

Visita questo link per maggiori informazioni sulla funzione ordinata: https://docs.python.org/2/library/functions.html#sorted


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}

Questo restituisce l'elenco delle coppie chiave-valore nel dizionario, ordinate per valore dal più alto al più basso:

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

Per il dizionario ordinato per chiave, utilizzare quanto segue:

sorted(d.items(), reverse=True)

Il ritorno è una lista di tuple perché i dizionari stessi non possono essere ordinati.

Questo può essere sia stampato che inviato ad ulteriori calcoli.


Se i tuoi valori sono numeri interi e usi Python 2.7 o successivi, puoi usare collections.Counter invece di dict . Il metodo most_common ti fornirà tutti gli elementi, ordinati in base al valore.


Se i valori sono numerici, puoi utilizzare anche Contatore dalle 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)]    

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}

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

Tecnicamente, i dizionari non sono sequenze e pertanto non possono essere ordinati. Puoi fare qualcosa del genere

sorted(a_dictionary.values())

assumere le prestazioni non è un grosso problema.


AGGIORNAMENTO: 5 DICEMBRE 2015 utilizzando Python 3.5

Anche se ho trovato la risposta accettata utile, sono stato anche sorpreso dal fatto che non è stato aggiornato per fare riferimento a OrderedDict dal modulo delle collezioni di librerie standard come un'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 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)])

Come sottolineato da Dilettant , Python 3.6 manterrà l'ordine ! Ho pensato di condividere una funzione che ho scritto che facilita l'ordinamento di un iterable (tuple, list, dict). In quest'ultimo caso, è possibile ordinare o su chiavi o valori e può prendere in considerazione il confronto numerico. Solo per> = 3.6!

Quando si tenta di utilizzare ordinati su un iterabile che contiene ad esempio stringhe e int, sort () fallirà. Ovviamente puoi forzare il confronto tra stringhe con str (). Tuttavia, in alcuni casi si desidera eseguire un confronto numerico effettivo in cui 12 è inferiore a 20 (che non è il caso nel confronto tra stringhe). Quindi sono venuto con il seguente. Quando si desidera il confronto numerico esplicito, è possibile utilizzare il flag num_as_num che tenterà di eseguire l'ordinamento numerico esplicito tentando di convertire tutti i valori in float. Se riesce, eseguirà l'ordinamento numerico, altrimenti ricorrerà al confronto tra stringhe.

Commenti per miglioramenti o richieste push benvenute.

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




dictionary