Come posso ordinare un dizionario per chiave?


941

Quale sarebbe un bel modo di andare da {2:3, 1:89, 4:5, 3:0}a {1:89, 2:3, 3:0, 4:5}?
Ho controllato alcuni post ma tutti usano l'operatore "ordinato" che restituisce tuple.


39
I dizionari sono intrinsecamente indifferenziati. La visualizzazione del dizionario è un'altra questione. Comunque, per cosa hai davvero bisogno di ordinarlo?
Karl Knechtel,

15
i dizionari non sono ordinati. non sono ancora arrivati. se vuoi esaminare gli elementi in ordine, dovresti fare qualcosa come hai detto usando ordinato come "per digitare in ordinato (d.keys ())" supponendo che d sia il nome del tuo dizionario
Ryan Haining

3
@KarlKnechtel - il mio caso d'uso è che ho un'applicazione CLI che ha un menu di base e le opzioni di menu sono in un dizionario come chiavi. Vorrei visualizzare i tasti in ordine alfabetico per la sanità mentale dell'utente.
Randy,


4
Si noti che i dadi sono ora ordinati in base all'ordine di inserimento (python 3.6+). Alcune risposte sotto indicano questo.
matiasg,

Risposte:


941

I dizionari Python standard non sono ordinati. Anche se hai ordinato le coppie (chiave, valore), non saresti in grado di memorizzarle dictin un modo tale da preservare l'ordinamento.

Il modo più semplice è usare OrderedDict, che ricorda l'ordine in cui gli elementi sono stati inseriti:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

Non importa come odviene stampato; funzionerà come previsto:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

Per gli utenti di Python 3, è necessario utilizzare .items()invece di .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5

1
Ho usato questo e funziona, immagino che sia più codice e ridondanza ma ottiene il lavoro fatto, # unordered dict d = {2: 3, 1:89, 4: 5, 3: 0} ordinatoDict = {} per la chiave ordinata (d.iterkeys ()): orderDict [chiave] = d [chiave]
Antony

4
@achrysochoou: se ha funzionato, deve essere stato per pura fortuna. Come ti è stato detto, i dizionari regolari non hanno alcun concetto di ordinamento, non importa se assegni le chiavi ordinate o in modo casuale.
Ricardo Cárdenes,

21
Per python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618,

10
python 3.7+ non dovrebbe aver bisogno di orderDict poiché ora ordina di default :-)
Aneuway

3
Dal manuale di Python 3.7.4: "L'esecuzione dell'elenco (d) su un dizionario restituisce un elenco di tutte le chiavi utilizzate nel dizionario, in ordine di inserimento". Quindi l'ordine di inserimento è qualcosa che viene preservato e su cui possiamo contare.
Mostafa Hadian,

415

I dizionari stessi non hanno ordinato articoli in quanto tali, se si desidera stamparli ecc. In un certo ordine, ecco alcuni esempi:

In Python 2.4 e versioni successive:

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

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

dà:

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

(Python sotto 2.4 :)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Fonte: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/


2
Puoi anche usare OrderedDict in Python 2.4+ come nella risposta di NPE
radtek,

1
e se stai usando oggetti () puoi farlo comefor key, value in sorted(mydict.items())"
beep_check

I dizionari stessi non hanno ordinato articoli in quanto tali -> non sono più veri!
minexew

Come mai, puoi spiegare?
James,

204

Dalla documentazione della collectionslibreria di Python :

>>> from collections import OrderedDict

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

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> 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)])

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

4
eccezionale! Ragazzi, se si desidera invertire l'ordine (crescente per decrescente), è sufficiente aggiungere reverse=Truead esempioOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia

1
In PyCharm, indipendentemente dal dizionario che uso, ricevo sempre questo avviso:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter

153

Per CPython / PyPy 3.6 e qualsiasi Python 3.7 o versioni successive, questo è facilmente eseguibile con:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}

3
Un altro modo di scrivere la stessa cosa è usare una comprensione: {key:d[key] for key in sorted(d.keys())}
flow2k,

41

Esistono numerosi moduli Python che forniscono implementazioni di dizionari che mantengono automaticamente le chiavi in ​​ordine. Considera il modulo di contenitori ordinati che è implementazioni pure-Python e fast-as-C. Esiste anche un confronto delle prestazioni con altre opzioni popolari confrontate tra loro.

L'uso di un dict ordinato è una soluzione inadeguata se è necessario aggiungere e rimuovere costantemente coppie chiave / valore durante l'iterazione.

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

Il tipo SortedDict supporta anche la ricerca e l'eliminazione della posizione indicizzata, cosa impossibile con il tipo di dict incorporato.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])

32

Semplicemente:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Produzione:

1 89
2 3
3 0
4 5

6
sdè un elenco di tuple, non un dizionario. (comunque utile.)
Nischi,

24

Come altri hanno già detto, i dizionari sono intrinsecamente non ordinati. Tuttavia, se il problema consiste semplicemente nella visualizzazione di dizionari in un modo ordinato, è possibile sovrascrivere il __str__metodo in una sottoclasse di dizionario e utilizzare questa classe di dizionario anziché quella incorporatadict . Per esempio.

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Nota, questo non cambia nulla sul modo in cui sono archiviate le chiavi, sull'ordine in cui torneranno quando si scorre su di esse, ecc., Sul modo in cui vengono visualizzate con printo sulla console di Python.


19

Trovato un altro modo:

import json
print json.dumps(d, sort_keys = True)

upd:
1. questo ordina anche gli oggetti nidificati (grazie a @DanielF).
2. I dizionari Python non sono ordinati, pertanto è possibile eseguirne la stampa o assegnare solo a str.


Ma questo ordina anche le chiavi degli oggetti nidificati, che potrebbero non essere desiderati.
Daniel F,

Si noti che questo ordina solo dizionari, non elenchi, ad esempio dict.keys () non verranno ordinati perché è un elenco.
Andrew,

16

In Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

1 89
2 3
3 0
4 5

13

Il dizionario Python non era stato ordinato prima di Python 3.6. Nell'implementazione CPython di Python 3.6, il dizionario mantiene l'ordine di inserimento. Da Python 3.7, questa diventerà una funzionalità linguistica.

Nel log delle modifiche di Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

L'aspetto che preserva l'ordine di questa nuova implementazione è considerato un dettaglio dell'implementazione e non dovrebbe essere invocato (questo potrebbe cambiare in futuro, ma si desidera avere questa nuova implementazione dict nella lingua per alcune versioni prima di cambiare le specifiche della lingua imporre la semantica di conservazione dell'ordine per tutte le implementazioni attuali e future di Python; ciò aiuta anche 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).

Nel documento di Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

L'esecuzione dell'elenco (d) su un dizionario restituisce un elenco di tutte le chiavi utilizzate nel dizionario, in ordine di inserimento (se si desidera ordinarlo , utilizzare invece ordinato (d)).

Quindi, diversamente dalle versioni precedenti, è possibile ordinare un dict dopo Python 3.6 / 3.7. Se vuoi ordinare un dict nidificato incluso il sub-dict all'interno, puoi fare:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: sort_dict(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb


11

Qui ho trovato la soluzione più semplice per ordinare il picton dict in base alla chiave pprint. per esempio.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

ma durante l'utilizzo di pprint restituirà dict ordinato

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}

10

C'è un modo semplice per ordinare un dizionario.

Secondo la tua domanda,

La soluzione è:

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Dove c, è il nome del tuo dizionario.)

Questo programma fornisce il seguente output:

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

come volevi.

Un altro esempio è:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Fornisce l'output:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Fornisce l'output:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Fornisce l'output:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

Quindi, modificandolo in chiavi, valori ed elementi, è possibile stampare come desiderato. Spero che questo aiuti!


8

Genererà esattamente quello che vuoi:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

Ma questo non è il modo corretto di farlo, perché potrebbe mostrare un comportamento distinto con dizionari diversi, che ho imparato di recente. Quindi il modo perfetto è stato suggerito da Tim nella risposta alla mia domanda che sto condividendo qui.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))

Che cosa significa "mostra un comportamento distinto con dizionari diversi"? Qual è il "comportamento distinto" che l'ordinamento non può gestire?
ingyhere il

6

Penso che la cosa più semplice sia ordinare il dict per chiave e salvare la chiave ordinata: coppia di valori in un nuovo dict.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

Per chiarire:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value

6

È possibile creare un nuovo dizionario ordinando il dizionario corrente in base alla chiave in base alla propria domanda.

Questo è il tuo dizionario

d = {2:3, 1:89, 4:5, 3:0}

Crea un nuovo dizionario d1 ordinando questo d usando la funzione lambda

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 dovrebbe essere {1: 89, 2: 3, 3: 0, 4: 5}, ordinato in base alle chiavi in ​​d.


5

I dadi di Python non sono ordinati. Di solito, questo non è un problema poiché il caso d'uso più comune è quello di fare una ricerca.

Il modo più semplice per fare ciò che vuoi sarebbe quello di creare un collections.OrderedDictinserimento degli elementi in ordine.

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

Se è necessario eseguire l'iterazione, come altri hanno suggerito sopra, il modo più semplice sarebbe quello di scorrere le chiavi ordinate. Examples-

Stampa valori ordinati per chiavi:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Ottieni un elenco di valori ordinati per chiavi:

values = [d[k] for k in sorted(d.keys())]

2
for k,value in sorted(d.items()):è meglio: evita di accedere nuovamente al dict in sequenza
Jean-François Fabre

4

Mi viene in mente l'ordinamento a riga singola.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

Spero che questo possa essere utile.


4

Questa funzione ordinerà ricorsivamente qualsiasi dizionario in base alla sua chiave. Cioè, se qualsiasi valore nel dizionario è anche un dizionario, anche questo verrà ordinato in base alla sua chiave. Se si esegue CPython 3.6 o versioni successive, è possibile apportare una semplice modifica per utilizzare un dictanziché un OrderedDict.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)

2

Ragazzi, state complicando le cose ... è davvero semplice

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

L'output è:

{'A':2,'B':1,'C':3}

Eseguito l'upgrade perché non sapevo che pprint ordinasse i dizionari per visualizzarli, ma l'OP ha davvero chiesto di "passare" dal dict non ordinato a quello ordinato, ovvero l'OP sembra voler qualcosa che rimanga in memoria, forse per un algoritmo che richiede chiavi ordinate
Capitano Lepton,

Questo metodo non consente l'assegnazione concatenata poiché pprint non ne restituisce alcuna. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (ultima chiamata più recente): file "<stdin>", riga 1, in <module> AttributeError: l'oggetto 'NoneType' non ha attributo 'tipo'

2

La soluzione più semplice è che dovresti ottenere un elenco di chiavi dict ordinate e quindi scorrere su dict. Per esempio

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

Di seguito sarà l'output (ordine desiderato)

e 30
b 13
d 4
c 2
a 1

2

Un modo semplice per farlo:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 

1

Un confronto temporale dei due metodi in 2.7 mostra che sono praticamente identici:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 

1
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)

1
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}


0

Il mio suggerimento è questo in quanto consente di ordinare un dict o di mantenere un dict ordinato mentre si stanno aggiungendo elementi e potrebbe essere necessario aggiungere articoli in futuro:

Costruisci un dictda zero mentre procedi. Avere una seconda struttura di dati, un elenco, con l'elenco di chiavi. Il pacchetto bisect ha una funzione insort che consente l'inserimento in un elenco ordinato, o ordina l'elenco dopo aver popolato completamente il tuo dict. Ora, quando si esegue l'iterazione del dict, si esegue invece l'iterazione dell'elenco per accedere a ciascuna chiave in modo ordinato senza preoccuparsi della rappresentazione della struttura del dict (che non è stata creata per l'ordinamento).


-1
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)

3
Ci sono altre 14 risposte. Puoi spiegare un po 'il tuo codice e perché potrebbe essere migliore rispetto alle altre soluzioni?
FelixSFD,

Downvoted - Codice piuttosto illeggibile con nomi di variabili brevi privi di significato l, l2, l3. Sembra essere un tentativo di un algoritmo indiretto e inefficiente senza conoscenza delle funzioni standard di Python, e in ogni caso non funziona se testato su un piccolo esempio nel post originale.
Capitano Lepton,
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.