Wie kann ich ein Wörterbuch nach Schlüssel sortieren?

940

Was wäre ein schöner Weg von {2:3, 1:89, 4:5, 3:0}zu {1:89, 2:3, 3:0, 4:5}?
Ich habe einige Beiträge überprüft, aber alle verwenden den Operator "sortiert", der Tupel zurückgibt.

Antonius
quelle
39
Wörterbücher sind an sich unsortiert. Das Anzeigen des Wörterbuchs ist eine andere Sache. Wie auch immer, wofür müssen Sie es wirklich sortieren?
Karl Knechtel
15
Wörterbücher werden nicht sortiert. sie sind einfach nicht. Wenn Sie die Elemente durchgehen möchten, müssen Sie etwas tun, wie Sie es gesagt haben, indem Sie sortiert wie "für Schlüssel in sortiert (d.keys ())" verwenden, vorausgesetzt, d ist der Name Ihres Wörterbuchs
Ryan Haining
3
@KarlKnechtel - Mein Anwendungsfall ist, dass ich eine CLI-Anwendung habe, die ein primitives Menü hat und die Menüoptionen in einem Wörterbuch als Schlüssel enthalten sind. Ich möchte die Tasten aus Gründen der Benutzerfreundlichkeit alphabetisch anzeigen.
Randy
4
Beachten Sie, dass Diktate jetzt nach Einfügereihenfolge sortiert sind (Python 3.6+). Einige Antworten unten weisen darauf hin.
Matiasg

Antworten:

940

Standard-Python-Wörterbücher sind ungeordnet. Selbst wenn Sie die (Schlüssel-, Wert-) Paare sortieren würden, könnten Sie sie nicht so speichern dict, dass die Reihenfolge erhalten bleibt.

Am einfachsten ist es OrderedDict, die Reihenfolge zu verwenden , in der die Elemente eingefügt wurden:

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

Es ist egal, wie der Weg odausgedruckt wird. es wird wie erwartet funktionieren:

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

Für Python 3-Benutzer muss Folgendes verwendet .items()werden .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
quelle
1
Ich habe dies verwendet und es funktioniert, ich denke, es ist mehr Code und Redundanz, aber es erledigt den Job (d.iterkeys ()): orderedDict [Schlüssel] = d [Schlüssel]
Antony
4
@achrysochoou: Wenn das funktioniert hat, muss es ein reines Glück gewesen sein. Wie Sie bereits erfahren haben, haben reguläre Wörterbücher kein Konzept zum Sortieren, unabhängig davon, ob Sie die Schlüssel sortiert oder zufällig zuweisen.
Ricardo Cárdenes
21
Für Python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
Aksh1618
10
Python 3.7+ sollte nicht bestellt werden müssenDict, da es jetzt standardmäßig bestellt :-)
Aneuway
3
Aus dem Python 3.7.4-Handbuch: "Wenn Sie Liste (d) für ein Wörterbuch ausführen, wird eine Liste aller im Wörterbuch verwendeten Schlüssel in Einfügereihenfolge zurückgegeben." Die Einfügereihenfolge bleibt also erhalten und wir können uns darauf verlassen.
Mostafa Hadian
415

Wörterbücher selbst haben keine Artikel als solche bestellt. Sollten Sie sie usw. in einer bestimmten Reihenfolge drucken möchten, finden Sie hier einige Beispiele:

In Python 2.4 und höher:

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

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

gibt:

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

(Python unter 2.4 :)

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

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

James
quelle
2
Sie können OrderedDict auch in Python 2.4+ verwenden, wie in der Antwort von NPE
radtek
1
und wenn Sie items () verwenden, können Sie dies wie for key, value in sorted(mydict.items())"
folgt
Wörterbücher selbst haben keine Artikel als solche bestellt -> nicht mehr wahr!
Minexew
Wie kommt es, kannst du das erklären?
James
204

Aus der collectionsBibliotheksdokumentation von 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)])
Dennis
quelle
4
genial! Jungs, wenn Sie die Reihenfolge umkehren möchten (aufsteigend bis absteigend), dann fügen Sie einfach reverse=TruezBOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
Benscabbia
1
In PyCharm erhalte ich unabhängig vom verwendeten Wörterbuch immer die folgende Warnung:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

Für CPython / PyPy 3.6 und Python 3.7 oder höher ist dies problemlos möglich mit:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
quelle
3
Eine andere Art, dasselbe zu schreiben, ist ein Verständnis: {key:d[key] for key in sorted(d.keys())}
flow2k
41

Es gibt eine Reihe von Python-Modulen, die Wörterbuchimplementierungen bereitstellen, mit denen die Schlüssel automatisch in sortierter Reihenfolge verwaltet werden. Betrachten Sie das sortierte Container- Modul, bei dem es sich um reine Python- und Fast-as-C-Implementierungen handelt. Es gibt auch einen Leistungsvergleich mit anderen beliebten Optionen, die miteinander verglichen werden .

Die Verwendung eines geordneten Diktats ist eine unzureichende Lösung, wenn Sie ständig Schlüssel / Wert-Paare hinzufügen und entfernen müssen, während Sie gleichzeitig iterieren.

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

Der Typ SortedDict unterstützt auch die Suche und das Löschen indizierter Speicherorte, was mit dem integrierten Diktattyp nicht möglich ist.

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

Einfach:

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

for k,v in sd:
    print k, v

Ausgabe:

1 89
2 3
3 0
4 5
user3769249
quelle
6
sdist eine Liste von Tupeln, kein Wörterbuch. (Immer noch nützlich.)
Nischi
24

Wie andere bereits erwähnt haben, sind Wörterbücher von Natur aus ungeordnet. Wenn das Problem jedoch nur darin besteht , Wörterbücher in geordneter Weise anzuzeigen , können Sie die __str__Methode in einer Wörterbuchunterklasse überschreiben und diese Wörterbuchklasse anstelle der integrierten verwenden dict. Z.B.

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}

Beachten Sie, dass dies nichts daran ändert, wie die Schlüssel gespeichert sind, in welcher Reihenfolge sie wiedergegeben werden, wenn Sie sie durchlaufen usw., wie sie mit printoder an der Python-Konsole angezeigt werden .

Brian
quelle
19

Einen anderen Weg gefunden:

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

upd:
1. Dadurch werden auch verschachtelte Objekte sortiert (danke @DanielF).
2. Python-Wörterbücher sind ungeordnet, daher kann dies nur gedruckt oder str zugewiesen werden.

tschesseket
quelle
Dies sortiert aber auch die Schlüssel verschachtelter Objekte, die möglicherweise nicht gewünscht werden.
Daniel F
Beachten Sie, dass hierdurch nur Wörterbücher sortiert werden, keine Listen, z. B. dict.keys (), die nicht sortiert werden, da es sich um eine Liste handelt.
Andrew
16

In Python 3.

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

gibt

1 89
2 3
3 0
4 5
Evgeny Tryastsin
quelle
13

Das Python-Wörterbuch war vor Python 3.6 ungeordnet. In der CPython-Implementierung von Python 3.6 behält das Wörterbuch die Einfügereihenfolge bei. Ab Python 3.7 wird dies zu einer Sprachfunktion.

Im Änderungsprotokoll von Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

Der auftragserhaltende Aspekt dieser neuen Implementierung wird als Implementierungsdetail betrachtet und sollte nicht als verlässlich angesehen werden (dies kann sich in Zukunft ändern, es ist jedoch erwünscht, diese neue Dikt-Implementierung für einige Releases in der Sprache zu haben, bevor die Sprachspezifikation geändert wird Dies trägt auch dazu bei, die Abwärtskompatibilität mit älteren Versionen der Sprache zu gewährleisten, in denen die zufällige Iterationsreihenfolge noch gültig ist (z. B. Python 3.5), um eine auftragserhaltende Semantik für alle aktuellen und zukünftigen Python-Implementierungen festzulegen.

Im Dokument von Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

Wenn Sie Liste (d) für ein Wörterbuch ausführen, wird eine Liste aller im Wörterbuch verwendeten Schlüssel in Einfügereihenfolge zurückgegeben (wenn Sie möchten, dass sie sortiert werden, verwenden Sie stattdessen einfach sortiert (d)).

Im Gegensatz zu früheren Versionen können Sie ein Diktat nach Python 3.6 / 3.7 sortieren. Wenn Sie ein verschachteltes Diktat einschließlich des darin enthaltenen Unterdiktats sortieren möchten, haben Sie folgende Möglichkeiten:

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

Guangyang Li
quelle
11

Hier habe ich eine einfachste Lösung gefunden, um das Python-Diktat nach Schlüssel zu sortieren pprint. z.B.

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

Bei Verwendung von pprint wird jedoch ein sortiertes Diktat zurückgegeben

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

Es gibt eine einfache Möglichkeit, ein Wörterbuch zu sortieren.

Nach Ihrer Frage,

Die Lösung ist :

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

(Wobei c der Name Ihres Wörterbuchs ist.)

Dieses Programm gibt folgende Ausgabe aus:

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

wie du wolltest.

Ein weiteres Beispiel ist:

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

Gibt die Ausgabe:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

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

Gibt die Ausgabe:[18, 24, 32, 36, 41]

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

Gibt die Ausgabe:

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

Wenn Sie es also in Schlüssel, Werte und Elemente ändern, können Sie wie gewünscht drucken. Hoffentlich hilft das!

Sree
quelle
8

Erzeugt genau das, was Sie wollen:

 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}

Dies ist jedoch nicht der richtige Weg, da dies ein unterschiedliches Verhalten mit verschiedenen Wörterbüchern zeigen kann, das ich kürzlich gelernt habe. Daher hat Tim In der Antwort auf meine Anfrage, die ich hier teile, einen perfekten Weg vorgeschlagen.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
jax
quelle
Was bedeutet "ein unterschiedliches Verhalten mit verschiedenen Wörterbüchern zeigen"? Was ist das "eindeutige Verhalten", das sortiert nicht verarbeiten kann?
Ingyhere
6

Ich denke, das Einfachste ist, das Diktat nach Schlüssel zu sortieren und das sortierte Schlüssel-Wert-Paar in einem neuen Diktat zu speichern.

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]

Um es klarer zu machen:

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
lallolu
quelle
6

Sie können ein neues Wörterbuch erstellen, indem Sie das aktuelle Wörterbuch nach Schlüssel gemäß Ihrer Frage sortieren.

Dies ist dein Wörterbuch

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

Erstellen Sie ein neues Wörterbuch d1, indem Sie dieses d mit der Lambda-Funktion sortieren

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

d1 sollte {1: 89, 2: 3, 3: 0, 4: 5} sein und nach den Schlüsseln in d sortiert sein.

Amit Prafulla
quelle
5

Python-Diktate sind nicht geordnet. Normalerweise ist dies kein Problem, da der häufigste Anwendungsfall darin besteht, eine Suche durchzuführen.

Der einfachste Weg, um das zu tun, was Sie wollen, besteht darin, collections.OrderedDictdie Elemente in sortierter Reihenfolge einzufügen.

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

Wenn Sie iterieren müssen, wie andere oben vorgeschlagen haben, besteht der einfachste Weg darin, über sortierte Schlüssel zu iterieren. Beispiele-

Druckwerte sortiert nach Schlüsseln:

# 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

Liste der nach Schlüsseln sortierten Werte abrufen:

values = [d[k] for k in sorted(d.keys())]
Ramashish Baranwal
quelle
2
for k,value in sorted(d.items()):ist besser: vermeidet den erneuten Zugriff auf das Diktat per Schlüssel in der Schleife
Jean-François Fabre
4

Ich habe eine einzeilige Diktatsortierung.

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

Hoffe das wird hilfreich sein.

Jeevan Chaitanya
quelle
4

Diese Funktion sortiert jedes Wörterbuch rekursiv nach seinem Schlüssel. Das heißt, wenn ein Wert im Wörterbuch auch ein Wörterbuch ist, wird auch dieser nach seinem Schlüssel sortiert. Wenn Sie mit CPython 3.6 oder höher arbeiten, kann eine einfache Änderung vorgenommen werden, um ein dictanstelle eines OrderedDictzu verwenden.

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)
Booboo
quelle
2

Leute, du machst die Dinge kompliziert ... es ist wirklich einfach

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

Die Ausgabe ist:

{'A':2,'B':1,'C':3}
Derick Fdo
quelle
Upvoted, weil ich nicht wusste, dass pprint Wörterbücher sortiert, um sie anzuzeigen, aber das OP hat wirklich gefragt, ob es von einem unsortierten zu einem sortierten Diktat übergehen soll, dh das OP scheint etwas zu wollen, das im Speicher sortiert bleibt, vielleicht für einen Algorithmus, der sortierte Schlüssel erfordert
Kapitän Lepton
Diese Methode erlaubt keine verkettete Zuweisung, da pprint keine zurückgibt. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (letzter Aufruf zuletzt): Datei "<stdin>", Zeile 1, in <module> AttributeError: Das Objekt 'NoneType' hat kein Attribut 'type'
2

Die einfachste Lösung besteht darin, dass Sie eine Liste mit Diktatschlüsseln in sortierter Reihenfolge erhalten und dann über Diktat iterieren. Zum Beispiel

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]

Es folgt die Ausgabe (absteigende Reihenfolge)

e 30
b 13
d 4
c 2
a 1
Shafiq
quelle
2

Ein einfacher Weg, dies zu tun:

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} 
pr94
quelle
1

Ein zeitlicher Vergleich der beiden Methoden in 2.7 zeigt, dass sie praktisch identisch sind:

>>> 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 
Jesuisme
quelle
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)
Mohammad Mahjoub
quelle
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]}
Mahdi Ghelichi
quelle
1

Oder verwenden Sie pandas,

Demo:

>>> d={'B':1,'A':2,'C':3}
>>> df=pd.DataFrame(d,index=[0]).sort_index(axis=1)
   A  B  C
0  2  1  3
>>> df.to_dict('int')[0]
{'A': 2, 'B': 1, 'C': 3}
>>> 

Sehen:

Dokumente davon

Dokumentation ganzer Pandas

U10-Vorwärts
quelle
0

Mein Vorschlag ist folgender: Sie können ein Diktat sortieren oder ein Diktat sortieren, während Sie Elemente hinzufügen, und müssen möglicherweise in Zukunft Elemente hinzufügen:

Bauen Sie eine dictvon Grund auf neu. Haben Sie eine zweite Datenstruktur, eine Liste, mit Ihrer Liste der Schlüssel. Das Halbierungspaket verfügt über eine Insort-Funktion, mit der Sie eine Liste sortieren oder Ihre Liste sortieren können, nachdem Sie Ihr Diktat vollständig ausgefüllt haben. Wenn Sie nun Ihr Diktat durchlaufen, durchlaufen Sie stattdessen die Liste, um in der richtigen Reihenfolge auf jeden Schlüssel zuzugreifen, ohne sich um die Darstellung der Diktatstruktur zu kümmern (die nicht zum Sortieren vorgesehen ist).

Demongolem
quelle
-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)
user7070507
quelle
3
Es gibt 14 weitere Antworten. Können Sie Ihren Code ein wenig erklären und warum er möglicherweise besser ist als die anderen Lösungen?
FelixSFD
Downvoted - Ziemlich unlesbarer Code mit kurzen bedeutungslosen Variablennamen l, l2, l3. Scheint ein Versuch eines indirekten und ineffizienten Algorithmus ohne Kenntnis der Python-Standardfunktionen zu sein und funktioniert auf jeden Fall nicht, wenn er an einem kleinen Beispiel im ursprünglichen Beitrag getestet wird.
Kapitän Lepton