Jak posortować słownik według wartości?


3422

Mam słownik wartości odczytanych z dwóch pól w bazie danych: pola ciągu i pola numerycznego. Pole ciągu jest unikalne, więc jest to klucz słownika.

Mogę sortować według kluczy, ale jak mogę sortować według wartości?

Uwaga: przeczytałem tutaj pytanie Przepełnienie stosu Jak posortować listę słowników według wartości słownika? i prawdopodobnie może zmienić mój kod, aby mieć listę słowników, ale ponieważ tak naprawdę nie potrzebuję listy słowników, chciałem wiedzieć, czy istnieje prostsze rozwiązanie do sortowania w kolejności rosnącej lub malejącej.


9
Struktura danych słownika nie ma właściwej kolejności. Możesz iterować przez to, ale nic nie gwarantuje, że iteracja będzie przebiegać według określonej kolejności. Jest to zgodne z projektem, więc najlepszym rozwiązaniem jest użycie innej struktury danych do reprezentacji.
Daishiman,

135
„sorted ()” może działać na słownikach (i zwraca listę posortowanych kluczy), więc myślę, że jest tego świadomy. Bez znajomości jego programu absurdalne jest mówienie komuś, że używa niewłaściwej struktury danych. Jeśli potrzebujesz 90% czasu na szybkie wyszukiwanie, prawdopodobnie jest to dyktando.
bobpaul

Wszystkie trzy dane wyjściowe (klucze, wartości, oba) do sortowania słowników są tutaj opisane w przejrzysty i zwięzły sposób: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman Klasa podstawowa może nie zostać zamówiona, ale oczywiście jest to Zamówienie .
Taylor Edmiston

1
W słownikach Python 3.6+ zachowaj kolejność wstawiania. Nie jest to oczywiście to samo, co możliwość sortowania ich według wartości, ale z drugiej strony nie można już powiedzieć, że „struktura danych słownikowych nie ma właściwej kolejności”.
Konrad Kocik,

Odpowiedzi:


4945

Python 3.6+

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
{k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

Starszy Python

Nie można posortować słownika, aby uzyskać reprezentację posortowanego słownika. Słowniki są z natury uporządkowane, ale inne typy, takie jak listy i krotki, nie są. Potrzebujesz więc uporządkowanego typu danych do reprezentowania posortowanych wartości, które będą listą - prawdopodobnie listą krotek.

Na przykład,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_xbędzie listą krotek posortowaną według drugiego elementu w każdej krotce. dict(sorted_x) == x.

A dla tych, którzy chcą sortować według kluczy zamiast wartości:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

W Python3, ponieważ rozpakowywanie nie jest dozwolone [1] , możemy użyć

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

Jeśli chcesz, aby dane wyjściowe były w formie nagrania, możesz użyć collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
dla czasów różnych sortowania słowników według schematów wartości: writeonly.wordpress.com/2008/08/30/…
Gregg Lind

164
sorted_x.reverse()da ci malejącą kolejność (według drugiego elementu krotki)
powiedział imu apale

414
saidimu: Ponieważ już korzystamy sorted(), przekazywanie reverse=Trueargumentu jest znacznie wydajniejsze .
rmh

121
W python3 użyłem lambda: sorted(d.items(), key=lambda x: x[1]). Czy to zadziała w Pythonie 2.x?
Keyo

84
OrdersDict dodano do kolekcji w 2.7. Przykład sortowania pokazany na: docs.python.org/library/…
monkut

1262

Tak prosty jak: sorted(dict1, key=dict1.get)

W rzeczywistości możliwe jest „sortowanie według wartości słownikowych”. Ostatnio musiałem to zrobić w Code Golf (pytanie o przepełnienie stosu Code golf: Wykres częstotliwości słów ). Skrócony, problem był tego rodzaju: biorąc pod uwagę tekst, policz, jak często napotyka się każde słowo, i wyświetl listę najważniejszych słów posortowanych według malejącej częstotliwości.

Jeśli konstruujesz słownik ze słowami jako kluczami i liczbą wystąpień każdego słowa jako wartością, uprościsz tutaj:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
    d[w] += 1

następnie możesz uzyskać listę słów, uporządkowaną według częstotliwości użycia z sorted(d, key=d.get)- sortowanie iteruje się po klawiszach słownika, używając liczby wystąpień słów jako klucza sortowania.

for w in sorted(d, key=d.get, reverse=True):
    print(w, d[w])

Piszę to szczegółowe wyjaśnienie, aby zilustrować, co ludzie często rozumieją przez: „Mogę łatwo posortować słownik według klucza, ale jak sortować według wartości” - i myślę, że oryginalny post próbował rozwiązać taki problem. Rozwiązaniem jest zrobienie listy kluczy w oparciu o wartości, jak pokazano powyżej.


31
Jest to również dobre, ale key=operator.itemgetter(1)powinno być bardziej skalowalne pod względem wydajności niżkey=d.get
smci

3
@raylu Za pomocą itemgetter obserwuję zachowanie „nie działa”: ----- from operator import itemgetter d = {"a":7, "b":1, "c":5, "d":3} sorted_keys = sorted(d, key=itemgetter, reverse=True) for key in sorted_keys: print "%s: %d" % (key, d[key]) ----- -> b: 1 c: 5 a: 7 d: 3 Wyniki zmieniają się za każdym razem, gdy uruchamiam kod: dziwne . (przepraszam, nie mogę poprawnie wyświetlić kodu)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)and for key, val in sorted_keys: print "%s: %d" % (key, val)- itemgetter tworzy funkcję, gdy jest wywołana, nie używasz jej bezpośrednio jak w twoim przykładzie. A zwykła iteracja na dykcie używa kluczy bez wartości
Izkata,

18
przyszedłem z przyszłości, aby ci powiedzieć collections.Counter, która ma most_commonmetodę, która może cię zainteresować :)
Eevee

2
@Eevee - istnieje ryzyko, że zostanie źle zrozumiany w krótkich komentarzach innych niż f2f. Amuzing tidbit: collections.Counterzostał dodany w wersji 2.7, która została wydana prawie dokładnie 7 lat temu! (Wtedy nie wiedziałem o tym - a poza tym unikałbym go w golfie kodowym dla zwięzłości, która jest jedyną obsesją gry)
Nas Banov

857

Możesz użyć:

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

Spowoduje to sortowanie słownika według wartości każdego wpisu w słowniku od najmniejszej do największej.

Aby posortować w kolejności malejącej, po prostu dodaj reverse=True:

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

Wejście:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}
a = sorted(d.items(), key=lambda x: x[1])    
print(a)

Wynik:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]

Z tego, co widziałem ( docs.python.org/2/library/… ), istnieje klasa o nazwie OrdersDict, którą można sortować i zachowywać porządek, wciąż będąc słownikiem. Z przykładów kodu możesz użyć lambda, aby go posortować, ale nie wypróbowałem go osobiście: P
UsAndRufus

53
Wolałbym key=lambda (k, v): vosobiście
Claudiu,

35
@Claudiu Podoba mi się również ta (k, v)składnia, ale nie jest ona dostępna w Pythonie 3, w którym usunięto rozpakowywanie parametrów krotki .
Bob Stein,

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

3
Nie. Utworzenie dykta z posortowanej listy krotek ponownie zabija porządek ...
Jean-François Fabre

233

Dykty nie mogą być sortowane, ale możesz zbudować z nich posortowaną listę.

Posortowana lista wartości dict:

sorted(d.values())

Lista par (klucz, wartość), posortowana według wartości:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))

W jakiej kolejności są umieszczone klucze o tej samej wartości? Najpierw posortowałem listę według kluczy, a następnie według wartości, ale kolejność kluczy o tej samej wartości nie pozostaje.
SabreWolfy,

1
Dykty można teraz sortować, zaczynając od CPython 3.6 i wszystkich innych implementacji Pythona od 3.7
Boris

161

W najnowszym Pythonie 2.7 mamy nowy typ OrdersDict , który pamięta kolejność dodawania elementów.

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

Aby utworzyć nowy uporządkowany słownik z oryginału, sortuj według wartości:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

OrDERDict zachowuje się jak normalny dykt:

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

5
Nie o to chodzi w pytaniu - nie chodzi o utrzymanie kolejności kluczy, ale o „sortowanie według wartości”
Nas Banov

10
@Nas Banov: NIE sortuje według klucza. sortuje w kolejności, tworzymy przedmioty. w naszym przypadku sortujemy według wartości. niestety wybrano 3-elementowy dykt, więc kolejność była taka sama, gdy posortowano voth według wartości i klucza, więc rozwinąłem przykładowy dykt.
mykhal

sorted(d.items(), key=lambda x: x[1])Czy potrafisz wyjaśnić, co to xznaczy, dlaczego może zabrać x[1]lambda? Dlaczego tak nie jest x[0]? Dziękuję Ci bardzo!
JZAU,

1
@Boern d.items()zwraca podobny do listy kontener (key, value)krotek. [0]uzyskuje dostęp do pierwszego elementu krotki - klucza - i [1]dostępu do drugiego elementu - wartości.
BallpointBen

2
Uwaga: Począwszy od 3.6 (w szczegółach realizacji CPython / pypy), a od 3,7 (jako gwarancja języka Python), zwykły dictjest wstawienie uporządkowane, tak więc można po prostu zastąpić OrderedDictz dictkodu działa na nowoczesnym Pythonie. OrderedDictnie jest już tak naprawdę potrzebny, chyba że musisz zmienić kolejność istniejących dict(z move_to_end/ popitem) lub potrzebujesz porównań równości, aby rozróżniać zamówienia. Zużywa o wiele więcej pamięci niż zwykły dict, więc jeśli możesz, dictto droga.
ShadowRanger,

104

AKTUALIZACJA: 5 GRUDNIA 2015 r. Przy użyciu języka Python 3.5

Chociaż uznałem, że zaakceptowana odpowiedź jest przydatna, zdziwiłem się również, że nie została zaktualizowana, aby odwoływać się do OragedDict ze standardowego modułu zbiorów bibliotecznych jako realnej, nowoczesnej alternatywy - zaprojektowanej w celu rozwiązania dokładnie tego rodzaju problemu.

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

Oficjalna dokumentacja OrdersDict również oferuje bardzo podobny przykład, ale używając lambda dla funkcji sortowania:

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

86

Prawie tak samo jak odpowiedź Hanka Gaya :

sorted([(value,key) for (key,value) in mydict.items()])

Lub lekko zoptymalizowany, jak sugerował John Fouhy:

sorted((value,key) for (key,value) in mydict.items())

9
... i jak w przypadku odpowiedzi Hanka Gaya, nie potrzebujesz nawiasów kwadratowych. sorted () chętnie przyjmie dowolną iterowalność, na przykład wyrażenie generatora.
John Fouhy,

Być może nadal będziesz musiał zamienić elementy krotki (wartość, klucz), aby uzyskać (klucz, wartość). Potrzebne jest zatem kolejne zrozumienie listy. [(key, value) for (value, key) in sorted_list_of_tuples]
powiedział imu apale

nie, lepiej zostawić nawiasy kwadratowe, ponieważ i sortedtak trzeba będzie odbudować listę, a przebudowywanie z gencomp będzie szybsze. Dobry do kodowania, zły dla prędkości. Zachowaj brzydką ([])wersję.
Jean-François Fabre

75

Korzystanie z namedtuple często może być bardzo przydatne . Na przykład masz słownik „nazwa” jako klucze i „wynik” jako wartości i chcesz posortować według „wynik”:

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

sortowanie najpierw od najniższego wyniku:

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

sortowanie najpierw z najwyższym wynikiem:

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

Teraz możesz uzyskać nazwę i wynik, powiedzmy, drugiego najlepszego gracza (indeks = 1) bardzo pythonicznie:

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

Jak mogę przekonwertować go z powrotem na słownik?
rowana

as_list = [Player (v, k) for (k, v) in d.items ()] as_dict = dict ((p.name, p.score) for p in as_list)
Remi

72

Począwszy od Python 3.6 wbudowany słownik zostanie zamówiony

Dobra wiadomość, więc oryginalny przypadek użycia OP dla par mapowania pobranych z bazy danych z unikalnymi identyfikatorami łańcuchów jako kluczami i wartościami liczbowymi jako wartościami do wbudowanego dict Pythona v3.6 +, powinien teraz przestrzegać kolejności wstawiania.

Jeśli powiedz wynikowe wyrażenia z dwóch kolumn z zapytania do bazy danych, takie jak:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

będą przechowywane w dwóch krotkach Pythona, k_seq i v_seq (wyrównane według indeksu numerycznego i oczywiście o tej samej długości), a następnie:

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

Pozwól na wyjście później jako:

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

ustępując w tym przypadku (dla nowego wbudowanego słownika Python 3.6+!):

foo 0
bar 1
baz 42

w tym samym porządku według wartości v.

Gdzie w instalacji Pythona 3.5 na moim komputerze daje on obecnie:

bar 1
foo 0
baz 42

Detale:

Jak zaproponował Raymond Hettinger w 2012 r. (Por. Poczta na python-dev z tematem „Bardziej kompaktowe słowniki z szybszą iteracją” ), a teraz (w 2016 r.) Ogłoszony w mailu Victora Stinnera do python-dev z tematem Dict Python 3.6 staje się kompaktowy i dostaje wersję prywatną, a słowa kluczowe zostają uporządkowane ”z powodu poprawki / wdrożenia wydania 27350 „ Kompaktowy i uporządkowany dykt ” w Pythonie 3.6 będziemy teraz mogli użyć wbudowanego dykta do utrzymania kolejności wstawiania !!

Mamy nadzieję, że doprowadzi to do wdrożenia cienkiej warstwy OrdersDict jako pierwszego kroku. Jak wskazał @ JimFasarakis-Hilliard, niektórzy zobaczą przypadki użycia dla typu OrdersDict również w przyszłości. Myślę, że cała społeczność Pythona dokładnie sprawdzi, czy to wytrzyma próbę czasu i jakie będą kolejne kroki.

Czas przemyśleć nasze nawyki programistyczne, aby nie przegapić możliwości, jakie daje stabilne porządkowanie:

  • Argumenty słów kluczowych i
  • (pośrednie) przechowywanie nagrań

Po pierwsze, ponieważ w niektórych przypadkach ułatwia wysyłanie przy wdrażaniu funkcji i metod.

Drugi, ponieważ zachęca do łatwiejszego wykorzystania dicts jako magazynu pośredniego w rurociągach przetwórczych.

Raymond Hettinger uprzejmie dostarczył dokumentację wyjaśniającą „ The Tech Behind Python 3.6 Dictionaries ” - z prezentacji w San Francisco Python Meetup Group 2016-DEC-08.

I może całkiem sporo stron z pytaniami i odpowiedziami o wysokim przepełnieniu stosu otrzyma warianty tych informacji i wiele wysokiej jakości odpowiedzi będzie wymagać aktualizacji dla każdej wersji.

Zastrzeżenie Emptor (ale także patrz poniżej aktualizacja 2017-12-15):

Jak słusznie zauważa @ajcr: „Aspekt utrzymywania porządku w tej nowej implementacji jest uważany za szczegół implementacji i nie należy na nim polegać”. (z whatsnew36 ) nie wybieranie nitów, ale cytat został nieco pesymistyczny ;-). Kontynuuje jako „(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, aby narzucić obowiązującą semantykę zachowującą porządek dla wszystkich bieżących i przyszłych implementacji Pythona; to również pomaga zachować kompatybilność wsteczną ze starszymi wersjami języka, w którym wciąż obowiązuje kolejność losowych iteracji, np. Python 3.5). ”

Tak jak w niektórych ludzkich językach (np. Niemiecki), użycie kształtuje język, a wola została teraz zadeklarowana ... w whatsnew36 .

Aktualizacja 15.12.2017:

W liście do listy python-dev Guido van Rossum oświadczył:

Zrób to tak. „Dict utrzymuje kolejność wstawiania” to orzeczenie. Dzięki!

Tak więc efekt uboczny CPython wersji 3.6 porządkowania wstawiania dyktów staje się teraz częścią specyfikacji języka (a nie tylko szczegółem implementacji). Ten wątek pocztowy zawierał również niektóre wyróżniające się cele projektowe, o collections.OrderedDictczym przypomniał Raymond Hettinger podczas dyskusji.


15
Należy podkreślić ostrzeżenie na stronie „whatsnew”, do której prowadzisz link: aspekt nowej implementacji dotyczący zachowania porządku jest uważany za szczegół implementacji i nie można na nim polegać . Nikt nie powinien zakładać, że dicttyp będzie przestrzegał kolejności wstawiania w swoim kodzie. Nie jest to część definicji języka, a implementacja może ulec zmianie w każdej przyszłej wersji. Kontynuuj używanie, OrderedDictaby zagwarantować zamówienie.
Alex Riley,

@ajcr dziękuję za zastrzeżenie, bardzo doceniane - ponieważ buźki i być może zostały wplecione w moją odpowiedź, powinny one wskazywać, zmiana jest ogromna, ale oczywiście dostępna tylko dla CPython (implementacja referencyjna) i PyPy. Coś zupełnie innego ... Rzadko mówię o szczegółach niezwiązanych z implementacją podczas kodowania instrukcji człowiek-maszyna. Gdyby to był tylko Jython ;-) ... Mógłbym nie mieć odwagi go napisać.
Dilettant,

OrderedDictna pewno nie zostanie porzucony; zamiast tego stanie się cienkim opakowaniem wokół bieżącej implementacji dict (więc możesz dodać, że stanie się również bardziej kompaktowy). Dodanie tego fragmentu do ImportErrornie jest najlepszym pomysłem, ponieważ wprowadza w błąd czytelników, które OrderedDictnie mają sensu.
Dimitris Fasarakis Hilliard,

@ JimFasarakis-Hilliard dziękuję za opinie. „Najlepsze pomysły” rozśmieszyły mnie - przyszłość często jest trudna do przewidzenia. Ale podoba mi się twoja sugestia sprawdzi źródła, wypróbuje ją, a następnie odpowiednio zaktualizuje odpowiedź. Dzięki jeszcze raz.
Dilettant,

8
@AlexRiley To zastrzeżenie nie jest już dokładne. Python3.7 gwarantuje uporządkowane słowniki.
gerrit

42

Miałem ten sam problem i rozwiązałem go w następujący sposób:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(Ludzie, którzy odpowiedzieli „Nie można posortować nagrania”, nie przeczytali pytania! W rzeczywistości „Mogę sortować według kluczy, ale jak mogę sortować według wartości?” Wyraźnie oznacza, że ​​chce listy klucze posortowane według wartości ich wartości).

Zauważ, że kolejność nie jest dobrze zdefiniowana (klucze o tej samej wartości będą w dowolnej kolejności na liście wyników).


1
Brakuje wartości w wyniku
Dejell

Pamiętaj, że zarówno iterujesz słownik, jak i pobierasz wartości według klucza, więc pod względem wydajności nie jest to optymalne rozwiązanie.
Ron Klein,

1
@Dejell: jak mówi współtwórca, interpretuje pytanie jako „czy mogę uzyskać listę kluczy posortowanych według wartości”. Nie potrzebujemy wartości w wyniku, mamy je w słowniku.
Max.

36

Jeśli wartości są liczbowe, możesz także użyć Counterz kolekcji .

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    

co jeśli słownik jest >>> x = {'hello': 1, 'python': 5, 'world': 300}
James Sapam

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()daje [('world', 300), ('python', 5), ('hello', 1)]. W rzeczywistości działa to dla każdego rodzaju wartości możliwej do sortowania (chociaż wiele innych operacji Licznika wymaga, aby wartości były porównywalne z ints).
lvc

34

W Pythonie 2.7 po prostu wykonaj:

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

skopiuj-wklej z: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Cieszyć się ;-)


25

To jest kod:

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

Oto wyniki:

Oryginalny

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

Ranga

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

25

Wypróbuj następujące podejście. Zdefiniujmy słownik o nazwie mydict z następującymi danymi:

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

Gdyby ktoś chciał posortować słownik według kluczy, mógłby zrobić coś takiego:

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

Powinno to zwrócić następujące dane wyjściowe:

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

Z drugiej strony, jeśli ktoś chciałby posortować słownik według wartości (jak zadaje pytanie), mógłby wykonać następujące czynności:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

Wynik tego polecenia (sortowanie słownika według wartości) powinien zwrócić następujące informacje:

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

Niesamowite! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):pozwala sortować według podklucza
Andomar

daje mi błąd składniowy w pobliżu lambda w Python3
Elahi

21

Począwszy od Pythona 3.6, dictobiekty są teraz uporządkowane według kolejności wstawiania. Jest to oficjalnie zawarte w specyfikacji Python 3.7.

>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

Wcześniej musiałeś użyć OrderedDict.

Dokumentacja Python 3.7 mówi:

Zmieniono w wersji 3.7: kolejność wstawiania słownika jest gwarantowana. To zachowanie było szczegółową implementacją CPython z 3.6.


działa świetnie! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))dla DESC
vizyourdata,

20

Możesz także utworzyć „indeks odwrócony”

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

Teraz twoja odwrotność ma wartości; każda wartość ma listę odpowiednich kluczy.

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

19

Możesz użyć licznika collections.Counter . Uwaga: będzie to działać zarówno dla wartości liczbowych, jak i nienumerycznych.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

7
Czym różni się to od odpowiedzi Ivana Sasa ?
Peter Mortensen

15

Możesz użyć pomijania, który jest słownikiem trwale posortowanym według wartości.

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

Jeśli użyjesz keys(), values()albo items()będziesz iterował w posortowanej kolejności według wartości.

Jest realizowany przy użyciu struktury danych listy pominięć.


czy możemy zmienić kolejność sortowania, w tej chwili to wysyłanie, ale chcę to robić.
Suleman Elahi

afaik musiałbyś zanegować swoje wartości, aby odwrócić kolejność
malthe

wow, nie myślę tak ... dzięki.
Suleman Elahi

14

Możesz także użyć funkcji niestandardowej, którą można przekazać do klucza.

def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)

12
from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict

2
pytanie brzmiało: sortuj według wartości, a nie według kluczy ... Lubię widzieć funkcję. Możesz importować kolekcje i oczywiście używać posortowanych (data.values ​​())
Remi

10

Jak zauważył Dilettant , Python 3.6 zachowa teraz porządek ! Pomyślałem, że podzielę napisaną przeze mnie funkcję, która ułatwia sortowanie iterowalnych (krotka, lista, dyktafon). W tym drugim przypadku można sortować według kluczy lub wartości i może ono uwzględniać porównanie numeryczne.Tylko dla> = 3,6!

Gdy spróbujesz użyć sorted na iterable, który przechowuje np. Łańcuchy, jak również ints, sorted () zakończy się niepowodzeniem. Oczywiście możesz wymusić porównanie ciągów za pomocą str (). Jednak w niektórych przypadkach chcesz dokonać rzeczywistego porównania numerycznego, gdzie 12jest mniejsze niż 20(co nie ma miejsca w porównaniu ciągów). Więc wymyśliłem następujące. Jeśli chcesz jawnego porównania numerycznego, możesz użyć flagi, num_as_numktóra spróbuje przeprowadzić jawne sortowanie numeryczne, próbując przekonwertować wszystkie wartości na zmiennoprzecinkowe. Jeśli to się powiedzie, przeprowadzi sortowanie numeryczne, w przeciwnym razie użyje porównania ciągów.

Komentarze do ulepszeń lub prośby push są mile widziane.

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

9

Oto rozwiązanie wykorzystujące zip d.values()id.keys() . Kilka linii w dół tego linku (w obiektach widoku słownika) to:

Pozwala to na tworzenie par (wartość, klucz) za pomocą zip (): pairs = zip (d. Wartości (), d. Klucze ()).

Możemy więc wykonać następujące czynności:

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

9

Oczywiście pamiętaj, że musisz użyć, OrderedDictponieważ zwykłe słowniki Pythona nie zachowują oryginalnej kolejności.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))

Jeśli nie masz języka Python w wersji 2.7 lub nowszej, najlepsze, co możesz zrobić, to iterować wartości w funkcji generatora. (Jest to OrderedDict2,4 i 2,6 tutaj , ale

a) Nie wiem, jak dobrze to działa

i

b) Oczywiście musisz go pobrać i zainstalować. Jeśli nie masz dostępu administracyjnego, obawiam się, że ta opcja jest niedostępna).


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

Możesz także wydrukować każdą wartość

for bleh, meh in gen(myDict):
    print(bleh, meh)

Pamiętaj, aby usunąć nawiasy po wydrukowaniu, jeśli nie używasz języka Python 3.0 lub nowszego


zwykłe słowniki Pythona nie zachowują oryginalnej kolejności - tak jak w Pythonie 3.7.
gerrit

7

Użyj ValueSortedDict z dicts :

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

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

6

Działa to w wersji 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)

6

Właśnie nauczyłem się odpowiednich umiejętności od Python for Everybody .

Możesz użyć tymczasowej listy, aby pomóc w sortowaniu słownika:

#Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# create a temporary list
tmp = []

# iterate through the dictionary and append each tuple into the temporary list 
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

Jeśli chcesz posortować listę w kolejności malejącej, po prostu zmień oryginalną linię sortowania na:

tmp = sorted(tmp, reverse=True)

Korzystając ze zrozumienia listy, jedną linijką byłoby:

#Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
#One liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
#One liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

Przykładowe dane wyjściowe:

#Asending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
#Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]

jest to sortowanie według kluczy, a nie według wartości.
Rubel

Jeśli chcesz wydrukować go w formacie początkowym, powinieneś: wydrukować ([(k, v) dla v, k posortowane ([(v, k) dla k, v in d.items ()])]). Dane wyjściowe to: [(„pomarańczowy”, 1.0), („jabłko”, 500.1), („ananas”, 789.0), („banan”, 1500,2)]. Gdy [(k, v) dla v, k jest posortowane ([(v, k) dla k, v w d.items ()], reverse = True)] wyjście to: [('banana', 1500.2), („ananas”, 789.0), („jabłko”, 500.1), („pomarańczowy”, 1.0)]
Hermes Morales

5

Iteruj przez dykt i sortuj je według wartości w porządku malejącym:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

5

Jeśli twoje wartości są liczbami całkowitymi i używasz języka Python 2.7 lub nowszego, możesz użyć collections.Counterzamiast niego dict. Ta most_commonmetoda da ci wszystkie elementy posortowane według wartości.


5

Dla kompletności zamieszczam rozwiązanie za pomocą heapq . Uwaga: ta metoda będzie działać zarówno dla wartości liczbowych, jak i nienumerycznych

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

4

Ze względu na wymagania dotyczące zachowania kompatybilności wstecznej ze starszymi wersjami Pythona myślę, że rozwiązanie OrdersDict jest bardzo nierozsądne. Chcesz czegoś, co działa z Pythonem 2.7 i starszymi wersjami.

Ale rozwiązanie dotyczące kolekcji, o którym mowa w innej odpowiedzi, jest absolutnie doskonałe, ponieważ przekwalifikowujecie połączenie między kluczem a wartością, co w przypadku słowników jest niezwykle ważne.

Nie zgadzam się z wyborem numer jeden przedstawionym w innej odpowiedzi, ponieważ wyrzuca klucze.

Użyłem rozwiązania wspomnianego powyżej (kod pokazany poniżej) i zachowałem dostęp zarówno do kluczy, jak i wartości, aw moim przypadku kolejność była na wartościach, ale ważna była kolejność kluczy po zamówieniu wartości.

from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.