Jak mogę posortować słownik według klucza?

938

Jaki byłby to dobry sposób, aby przejść od {2:3, 1:89, 4:5, 3:0}do {1:89, 2:3, 3:0, 4:5}?
Sprawdziłem niektóre posty, ale wszystkie używają operatora „posortowanego”, który zwraca krotki.

Antony
źródło
39
Słowniki są z natury nieposortowane. Wyświetlanie słownika to inna sprawa. W każdym razie, po co tak naprawdę chcesz to sortować?
Karl Knechtel,
15
słowniki nie są sortowane. po prostu nie są. jeśli chcesz przejść przez elementy, aby zrobić coś takiego, jak powiedziałeś, używając sortowania, np. „dla klucza w sortowaniu (d.keys ())”, zakładając, że d to nazwa twojego słownika
Ryan Haining
3
@KarlKnechtel - moim przypadkiem użycia jest to, że mam aplikację CLI, która ma prymitywne menu, a opcje menu znajdują się w słowniku jako klucze. Chciałbym wyświetlić klawisze alfabetycznie dla zachowania rozsądku użytkownika.
Randy
4
Zauważ, że dyktanda są teraz uporządkowane według kolejności wstawiania (python 3.6+). Niektóre odpowiedzi poniżej wskazują na to.
matiasg

Odpowiedzi:

939

Standardowe słowniki w języku Python są nieuporządkowane. Nawet jeśli posortujesz pary (klucz, wartość), nie będziesz w stanie przechowywać ich w dictsposób, który zachowałby porządek.

Najprostszym sposobem jest użycie OrderedDict, które pamięta kolejność wstawiania elementów:

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

Nieważne, jak odjest wydrukowany; będzie działać zgodnie z oczekiwaniami:

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

W przypadku użytkowników Python 3 należy użyć .items()zamiast .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
źródło
1
Użyłem tego i działa, myślę, że jest więcej kodu i redundancji, ale wykonuje zadanie, # nieuporządkowany dykt d = {2: 3, 1:89, 4: 5, 3: 0} uporządkowanyDict = {} dla klucza posortowanego (d.iterkeys ()): orderDict [key] = d [key]
Antony
4
@achrysochoou: jeśli to zadziałało, musiało to być zwykłe szczęście. Jak już powiedziano, w zwykłych słownikach nie ma pojęcia sortowania, bez względu na to, czy przypisujesz klucze posortowane, czy losowo.
Ricardo Cárdenes
21
Dla python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618
10
Python 3.7+ nie powinien wymagać orderDict, ponieważ teraz domyślnie zamawia :-)
Aneuway
3
Z podręcznika Python 3.7.4: „Wykonywanie listy (d) w słowniku zwraca listę wszystkich kluczy używanych w słowniku, w kolejności wstawiania”. Tak więc kolejność wstawiania jest czymś, co zostaje zachowane i możemy na nim polegać.
Mostafa Hadian
415

Same słowniki nie mają jako takich uporządkowanych elementów, jeśli chcesz je wydrukować itp. W określonym porządku, oto kilka przykładów:

W Pythonie 2.4 i nowszych:

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

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

daje:

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

(Python poniżej 2.4 :)

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

Źródło: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/

James
źródło
2
Możesz także użyć OragedDict w python 2.4+ jak w odpowiedzi NPE
radtek
1
a jeśli korzystasz z item (), możesz to zrobić w następujący sposóbfor key, value in sorted(mydict.items())"
beep_check
Same słowniki nie mają takich pozycji -> już nie są prawdziwe!
minexew
Jak możesz to wyjaśnić?
James
204

Z dokumentacji biblioteki Pythonacollections :

>>> 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
źródło
4
niesamowite! Chłopaki, jeśli chcesz odwrócić kolejność (rosnąco TO malejąco), po prostu dodajesz reverse=Truenp.OrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia
1
W PyCharm, bez względu na słownik, którego używam, zawsze otrzymuję to ostrzeżenie:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

W przypadku CPython / PyPy 3.6 i dowolnego Pythona 3.7 lub nowszego można to łatwo zrobić za pomocą:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
źródło
3
Innym sposobem napisania tego samego jest użycie zrozumienia: {key:d[key] for key in sorted(d.keys())}
flow2k
41

Istnieje wiele modułów Python, które zapewniają implementacje słownikowe, które automatycznie utrzymują klucze w posortowanej kolejności. Rozważ moduł sortedcontainers , który jest implementacją czysto Python i Fast-as-C. Istnieje również porównanie wydajności z innymi popularnymi opcjami porównanymi ze sobą.

Korzystanie z zamówionego dykta jest nieodpowiednim rozwiązaniem, jeśli trzeba stale dodawać i usuwać pary klucz / wartość, a także iterować.

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

Typ SortedDict obsługuje również indeksowane wyszukiwanie i usuwanie lokalizacji, co nie jest możliwe w przypadku wbudowanego typu dict.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])
GrantJ
źródło
32

Po prostu:

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

for k,v in sd:
    print k, v

Wynik:

1 89
2 3
3 0
4 5
użytkownik3769249
źródło
6
sdto lista krotek, a nie słownik. (wciąż przydatne).
nischi
24

Jak wspomnieli inni, słowniki są z natury nieuporządkowane. Jeśli jednak problemem jest jedynie wyświetlanie słowników w uporządkowany sposób, można zastąpić __str__metodę w podklasie słownika i użyć tej klasy słownika zamiast wbudowanej dict. Na przykład.

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}

Zauważ, że nie zmienia to niczego w sposobie przechowywania kluczy, kolejności, w której powrócą podczas iteracji nad nimi itp., W jaki sposób są wyświetlane za pomocą printlub w konsoli Pythona.

Brian
źródło
19

Znaleziono inny sposób:

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

upd:
1. sortuje również zagnieżdżone obiekty (dzięki @DanielF).
2. Słowniki python są nieuporządkowane, dlatego można je drukować lub przypisywać tylko do str.

tschesseket
źródło
Ale to również sortuje klucze zagnieżdżonych obiektów, które mogą nie być pożądane.
Daniel F,
Zauważ, że sortuje to tylko słowniki, a nie listy, np. Dict.keys () nie będzie sortowane, ponieważ jest to lista.
Andrew
16

W Python 3.

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

daje

1 89
2 3
3 0
4 5
Evgeny Tryastsin
źródło
13

Słownik Pythona był nieuporządkowany przed Pythonem 3.6. W implementacji CPython w Pythonie 3.6 słownik zachowuje kolejność wstawiania. Od wersji Python 3.7 będzie to funkcja językowa.

W dzienniku zmian Pythona 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

Aspekt zachowywania porządku w tej nowej implementacji jest uważany za szczegół implementacji i nie należy na nim polegać (może się to zmienić w przyszłości, ale pożądane jest, aby ta nowa implementacja dict w języku była dostępna przez kilka wydań przed zmianą specyfikacji języka narzucenie semantyki zachowującej porządek dla wszystkich bieżących i przyszłych implementacji Pythona; pomaga to również zachować zgodność wsteczną ze starszymi wersjami języka, w którym nadal obowiązuje kolejność losowych iteracji, np. Python 3.5).

W dokumencie Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

Wykonywanie listy (d) w słowniku zwraca listę wszystkich kluczy używanych w słowniku, w kolejności wstawiania (jeśli chcesz go posortować, po prostu użyj sorted (d)).

Tak więc, w przeciwieństwie do poprzednich wersji, możesz posortować słownik po Pythonie 3.6 / 3.7. Jeśli chcesz posortować zagnieżdżony dykt, w tym sub-dykt wewnątrz, możesz:

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
źródło
11

Tutaj znalazłem najprostsze rozwiązanie do sortowania słownika python według klucza za pomocą pprint. na przykład.

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

ale podczas używania pprint zwróci posortowane dict

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}
Atul Arvind
źródło
10

Istnieje prosty sposób na posortowanie słownika.

Zgodnie z twoim pytaniem

Rozwiązaniem jest :

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

(Gdzie c to nazwa twojego słownika.)

Ten program daje następujące dane wyjściowe:

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

tak jak chciałeś.

Innym przykładem jest:

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

Daje wynik:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

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

Daje wynik:[18, 24, 32, 36, 41]

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

Daje wynik:

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

Dlatego zmieniając go w klucze, wartości i elementy, możesz drukować tak, jak chcesz. Mam nadzieję, że to pomaga!

Sree
źródło
8

Wygeneruje dokładnie to, co chcesz:

 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}

Ale to nie jest właściwy sposób, aby to zrobić, ponieważ może wykazywać wyraźne zachowanie z różnymi słownikami, których niedawno się nauczyłem. Dlatego w odpowiedzi na moje zapytanie, które tu udostępniam, Tim zaproponował doskonały sposób.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
jax
źródło
Co oznacza „wykazują różne zachowania w przypadku różnych słowników”? Jakie „odrębne zachowanie”, które posortowało, nie może sobie poradzić?
ingyhere
6

Myślę, że najłatwiej jest posortować dyktowanie według klucza i zapisać posortowaną parę klucz: wartość w nowym dykcie.

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]

Aby było to jaśniejsze:

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
źródło
6

Możesz utworzyć nowy słownik, sortując aktualny słownik według klucza zgodnie z pytaniem.

To jest twój słownik

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

Utwórz nowy słownik d1, sortując ten d za pomocą funkcji lambda

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

d1 powinno być {1: 89, 2: 3, 3: 0, 4: 5}, posortowane na podstawie kluczy z d.

Amit Prafulla
źródło
5

Dykty w języku Python nie są uporządkowane. Zwykle nie stanowi to problemu, ponieważ najczęstszym przypadkiem użycia jest wyszukiwanie.

Najprostszym sposobem na zrobienie tego, co chcesz, byłoby utworzenie collections.OrderedDictwstawiania elementów w posortowanej kolejności.

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

Jeśli potrzebujesz iteracji, jak sugerują inni powyżej, najprostszym sposobem byłoby iterowanie posortowanych kluczy. Przykłady

Wydrukuj wartości posortowane według kluczy:

# 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

Pobierz listę wartości posortowanych według kluczy:

values = [d[k] for k in sorted(d.keys())]
Ramashish Baranwal
źródło
2
for k,value in sorted(d.items()):jest lepsze: unika dostępu do dykta po raz kolejny w pętli
Jean-François Fabre
4

Wymyślam sortowanie pojedynczych wierszy.

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

Mam nadzieję, że to będzie pomocne.

Jeevan Chaitanya
źródło
4

Ta funkcja posortuje rekursywnie dowolny słownik według jego klucza. Oznacza to, że jeśli jakakolwiek wartość w słowniku jest również słownikiem, również zostanie posortowana według klucza. Jeśli korzystasz z CPython 3.6 lub nowszego, możesz dokonać prostej zmiany, dictzamiast używania 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)
Boo Boo
źródło
2

Faceci, których komplikujecie ... to naprawdę proste

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

Dane wyjściowe to:

{'A':2,'B':1,'C':3}
Derick Fdo
źródło
Głosowałem, ponieważ nie wiedziałem, że pprint sortuje słowniki, aby je wyświetlić, ale OP naprawdę zapytał o „przejście” z nieposortowanego do posortowanego słownika, tj. OP wydaje się chcieć czegoś, co pozostaje posortowane w pamięci, być może dla jakiegoś algorytmu wymagającego posortowanych kluczy
Kapitan Lepton,
Ta metoda nie pozwoli na przypisanie łańcuchowe, ponieważ pprint nie zwraca żadnego. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (ostatnie ostatnie wywołanie): Plik „<stdin>”, wiersz 1, w <module> AttributeError: Obiekt „NoneType” nie ma atrybutu „typ”
2

Najprostszym rozwiązaniem jest wyświetlenie listy kluczy do sortowania w kolejności sortowania, a następnie iteracji po dyktowaniu. Na przykład

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]

Następujące będzie wyjście (kolejność wycofywania)

e 30
b 13
d 4
c 2
a 1
Shafiq
źródło
2

Łatwy sposób to zrobić:

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
źródło
1

Porównanie czasowe dwóch metod w 2.7 pokazuje, że są one praktycznie identyczne:

>>> 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
źródło
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
źródło
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
źródło
1

Albo użyj pandas ,

Próbny:

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

Widzieć:

Dokumenty tego

Dokumentacja całych pand

U10 do przodu
źródło
0

Moja sugestia jest taka, ponieważ umożliwia sortowanie nagrania lub utrzymywanie go w porządku podczas dodawania elementów i może być konieczne dodanie elementów w przyszłości:

Zbuduj dictod zera w trakcie pracy. Mają drugą strukturę danych, listę z listą kluczy. Pakiet bisect ma funkcję insort, która umożliwia wstawianie do posortowanej listy lub sortowanie listy po całkowitym zapełnieniu słownika. Teraz, gdy wykonujesz iterację po swoim dyktando, zamiast tego iterujesz po liście, aby uzyskać dostęp do każdego klucza w uporządkowany sposób, nie martwiąc się o reprezentację struktury dykt (która nie została stworzona do sortowania).

demongolem
źródło
-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)
użytkownik7070507
źródło
3
Istnieje 14 innych odpowiedzi. Czy możesz trochę wyjaśnić swój kod i dlaczego może być lepszy niż inne rozwiązania?
FelixSFD
Downvoted - Dość nieczytelny kod z krótkimi, bezsensownymi nazwami zmiennych l, l2, l3. Wydaje się być próbą zastosowania pośredniego i nieefektywnego algorytmu bez znajomości standardowych funkcji Pythona, aw każdym razie nie działa, gdy jest testowany na małym przykładzie w oryginalnym poście.
Kapitan Lepton,