Pytanie Jak sortować słownik według wartości?


Mam słownik wartości odczytanych z dwóch pól w bazie danych: pole łańcuchowe i pole liczbowe. Pole string jest unikalne, więc jest kluczem do słownika.

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

Uwaga: Przeczytałem pytanie Stack Overflow Jak sortować listę słowników według wartości słownika w Pythonie? i prawdopodobnie mógłbym zmienić mój kod, żeby mieć listę słowników, ale ponieważ tak naprawdę nie potrzebuję listy słowników, chciałem wiedzieć, czy istnieje prostsze rozwiązanie.


2938
2018-03-05 00:49


pochodzenie


Struktura danych słownika nie ma właściwej kolejności. Można go iterować, ale nie ma nic, co zagwarantowałoby, że iteracja będzie następować po określonej kolejności. Jest to zgodne z projektem, więc najlepszym rozwiązaniem jest prawdopodobnie wykorzystanie struktury danych anohter do reprezentacji. - Daishiman
"sorted ()" może operować na słownikach (i zwraca listę posortowanych kluczy), więc myślę, że jest tego świadomy. Bez znajomości jego programu absurdem jest powiedzieć komuś, że używa niewłaściwej struktury danych. Jeśli potrzebujesz szybkiego wyszukiwania w 90% przypadków, to prawdopodobnie chcesz, aby dict. - bobpaul
Dla osób sugerujących, że jest to duplikat stackoverflow.com/questions/72899/... , to pytanie jest oznaczone jako duplikat tego pytania. - Marcin
Jeśli to możliwe, stwórz NumPy Series ze słownika i posortuj go za pomocą pandas.Series.order - Dror
Wszystkie trzy wyjścia (klucze, wartości, obie) do sortowania słowników są tutaj omówione w jasny i zwięzły styl: stackoverflow.com/questions/16772071/sort-dict-by-value-python - JStrahl


Odpowiedzi:


Nie można sortować słownika, aby uzyskać reprezentację posortowanego słownika. Słowniki są z natury pozbawione porządku, ale inne typy, takie jak listy i krotki, nie są. Tak więc potrzebujesz uporządkowanego typu danych do reprezentowania sortowanych 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_x będzie listą krotek posortowanych według drugiego elementu w każdej krotce. dict(sorted_x) == x.

A dla tych, którzy chcą sortować klucze 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 języku Python3, ponieważ rozpakowywanie nie jest dozwolone [1] możemy użyć

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

3555
2018-03-05 00:59



dla czasu na różne sortowanie słownikowe według schematów wartości: writeonly.wordpress.com/2008/08/30/... - Gregg Lind
sorted_x.reverse() da ci malejącą kolejność (według drugiego elementu krotki) - saidimu apale
saidimu: Ponieważ już używamy sorted(), znacznie wydajniej jest przekazać to reverse=True argument. - rmh
W python3 użyłem lambda: sorted(d.items(), key=lambda x: x[1]). Czy to działa w python 2.x? - Keyo
OrderedDict dodał do kolekcji w 2.7. Przykład sortowania pokazany na: docs.python.org/library/... - monkut


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

Cóż, faktycznie możliwe jest "sortowanie według wartości słownika". Ostatnio musiałem to zrobić w kwestii Code Golf (Stack Overflow) Code golf: Word chart chart). Skrócony, problem był tego rodzaju: podając tekst, policz, jak często każde słowo jest napotykane i wyświetla listę górnych słów, posortowaną według malejącej częstotliwości.

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

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

następnie możesz uzyskać listę słów uporządkowanych według częstotliwości używania sorted(d, key=d.get) - sortuje iteracje po kluczach 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 oznaczają przez "Mogę łatwo sortować słownik według klucza, ale jak sortować według wartości" - i uważam, że OP próbował rozwiązać ten problem. Rozwiązaniem jest sporządzenie listy kluczy na podstawie wartości, jak pokazano powyżej.


969
2017-07-05 08:01



Jest to również dobre, ale key=operator.itemgetter(1) powinien być bardziej skalowalny dla wydajności niż key=d.get - smci
Najpierw musisz: zaimportować kolekcje #, aby użyć defaultdict - rjurney
@raylu Obserwuję zachowanie "nie działa" przy użyciu itemgetter: ----- 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 odczytać kodu) - bli
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True) i for key, val in sorted_keys: print "%s: %d" % (key, val) - itemgetter tworzy funkcję po jej wywołaniu, nie używaj jej bezpośrednio, jak w twoim przykładzie. I zwykła iteracja na dyktafonie używa kluczy bez wartości - Izkata
przyszedłem z przyszłości, aby ci powiedzieć collections.Counter, który ma most_common metoda, która może Cię zainteresować :) - Eevee


Możesz użyć:

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

Spowoduje to posortowanie słownika według wartości każdego wpisu w słowniku od najmniejszego do największego.


607
2018-02-13 16:33



+1 Za bycie najczystszym rozwiązaniem. Jednak nie sortuje on słownika (tablica haszująca, nie jest możliwa), lecz zwraca uporządkowaną listę (key, value) krotki. - Keyo
@Keyo Jestem nowym użytkownikiem Pythona i natknąłem się na potrzebę posortowania słownika. I chcę się upewnić, że dobrze cię zrozumiałem: nie ma sposobu, aby użyć słownika lambda do sortowania słownika, prawda? - lv10
wolałbym key=lambda (k, v): v osobiście - Claudiu
@ Claudiu Podoba mi się to (k, v) również składnia, ale nie jest dostępna w Pythonie 3 gdzie rozpakowanie parametrów krotek zostało usunięte. - Bob Stein
@Nyxynyx Po prostu dodaj reverse=True wewnątrz posortowanego bitu (np sorted(a.items(), key=lambda x: x[1], reverse=True)) - Mathime


Dicts nie mogą być sortowane, ale możesz zbudować z nich uporządkowaną listę.

Posortowana lista wartości dyktowanych:

sorted(d.values())

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

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

165
2018-03-05 01:05



+1: posortowane (d.values ​​()) jest łatwiejsze do odczytania / zrozumienia niż posortowane Nas (dict1, key = dict1.get), a więc bardziej Pythoniczne. O czytelności, proszę również rozważyć moje namedtuple sugestia. - Remi
Jakie zamówienie są klucze o tej samej wartości? Najpierw posortowałem listę według kluczy, potem według wartości, ale kolejność klawiszy o tej samej wartości nie zostaje. - SabreWolfy
@ Remi, to są dwie różne rzeczy! sorted(d.values()) zwraca posortowaną listę wartości ze słownika, gdzie sorted(d, key=d.get) zwraca listę klawiaturaposortowane według wartości! Sposób inny. Jeśli nie widzisz potrzeby tego ostatniego, przeczytaj mój post powyżej dla przykładu "prawdziwego życia" - Nas Banov


W ostatnim Pythonie 2.7 mamy nowe OrderedDict type, który zapamiętuje 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]))

The OrderedDict zachowuje się jak normalny dict:

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

128
2017-07-05 02:50



Nie o to chodzi w tym pytaniu - nie chodzi o utrzymanie porządku kluczy, ale o "sortowanie według wartości" - Nas Banov
@Nas Banov: NIE sortuje według klucza. to sortowanie w kolejności, tworzymy elementy. w naszym przypadku sortujemy według wartości. niestety, 3-itemowy dykt został niestety wybrany, więc kolejność była taka sama, kiedy posortowano ją według wartości i klucza, więc rozszerzyłem przykładowy dykt. - mykhal
sorted(d.items(), key=lambda x: x[1]) Czy możesz wyjaśnić, co xoznacza, dlaczego może to potrwać x[1] do lambda? Dlaczego tak nie jest x[0]? Dziękuję Ci bardzo! - JZAU
@jie d.items() zwraca listę par klucz / wartość ze słownika i x jest elementem tej krotki. x[0] będzie kluczem i x[1] będzie wartością. Kiedy chcemy uporządkować wartość, mijamy x[1] do lambda. - CadentOrange
@ Boern d.items() zwraca kontener podobny do listy o wartości (key, value) krotki. [0] uzyskuje dostęp do pierwszego elementu krotki - klawisza - i [1] uzyskuje dostęp do drugiego elementu - wartości. - BallpointBen


AKTUALIZACJA: 5 GRUDNIA 2015 przy użyciu Pythona 3.5

Chociaż uznałem, że zaakceptowana odpowiedź jest przydatna, byłem również zaskoczony, że nie została ona zaktualizowana OrderedDict ze standardowej biblioteki kolekcje moduł jako realna, nowoczesna alternatywa - zaprojektowany, aby rozwiązać dokładnie ten typ 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)])

Oficjalny OrderedDict dokumentacja oferuje bardzo podobny przykład, ale z użyciem funkcji 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)])

75
2017-12-05 09:46





Często może być bardzo przydatny w użyciu namedtuple. Na przykład słownik "nazwa" jako klucze i "wynik" jako wartości, które chcesz sortować według "wyniku":

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

najpierw sortuj z najniższym wynikiem:

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

sortowanie z najwyższym wynikiem w pierwszej kolejności:

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

Teraz możesz uzyskać nazwę i wynik, powiedzmy, drugi najlepszy gracz (index = 1) bardzo Pythonically like this:

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

64
2017-08-30 00:30



Jak mogę go przekonwertować z powrotem na słownik? - rowana
as_list = [Player (v, k) dla (k, v) w d.items ()] as_dict = dict ((p.nazwa, p.score) dla p w as_list) - Remi


Podobnie jak odpowiedź Hanka Gaya;


    posortowane ([(wartość, klucz) dla (klucz, wartość) w usłudze mydict.items ()])

Lub zoptymalizowany nieco, jak sugeruje John Fouhy;


    posortowane ((wartość, klucz) dla (klucz, wartość) w usłudze mydict.items ())


57
2018-03-05 01:06



..i jak z odpowiedzią Hanka Gay'a, nie potrzebujesz kwadratowych nawiasów. sorted () z przyjemnością wybierze dowolną wartość, taką jak wyrażenie generatora. - John Fouhy
Być może nadal będziesz musiał zamienić elementy krotki (wartość, klucz) na koniec (klucz, wartość). Konieczne jest wtedy kolejne zrozumienie list. [(key, value) for (value, key) in sorted_list_of_tuples] - saidimu apale
nie, lepiej zostawić nawiasy kwadratowe, ponieważ sorted i tak będzie musiał przebudować listę, a przebudowanie z gencomp będzie szybsze. Dobry do kodowania, zły na szybkość. Zachowaj brzydki ([]) wersja. - Jean-François Fabre


Od teraz Python 3.6 wbudowany dykt zostanie zamówiony

Dobra wiadomość, więc oryginalny przypadek użycia mapowania par pobranych z bazy danych z unikalnymi identyfikatorami łańcuchów jako kluczy i wartości numerycznych jako wartości do wbudowanego języka Python v3.6 + powinien teraz respektować kolejność wstawiania.

Jeśli powiesz wynikowe dwa wyrażenia tabel kolumn z zapytania bazy danych, takie jak:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

byłby przechowywany w dwóch krotkach Pythona, k_seq i v_seq (wyrównanych do indeksu liczbowego 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))

Zezwalaj na późniejsze wyprowadzanie jako:

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

plonowanie w tym przypadku (dla nowego wbudowanego Dicta Pythona 3.6+!):

foo 0
bar 1
baz 42

w tym samym porządku na wartość v.

Gdzie w Pythonie 3.5 zainstalowałem na moim komputerze, obecnie daje:

bar 1
foo 0
baz 42

Detale:

Jak zaproponował w 2012 r. Raymond Hettinger (por. Mail na python-dev z tematem "Więcej kompaktowych słowników z szybszą iteracją") i teraz (w 2016 r.) ogłosił w mailu Victora Stinnera do Pythona-dev z tematem "Dict Python 3.6 staje się zwarty i uzyskuje wersję prywatną, a słowa kluczowe stają się uporządkowane" ze względu na naprawę / implementację problemu 27350 "Kompaktowy i uporządkowany dykt" w Pythonie 3.6 będziemy teraz mogli używać wbudowanego Dicta do utrzymywania kolejności wstawiania !!

Mam nadzieję, że doprowadzi to do wdrożenia cienkiej warstwy OrderedDict jako pierwszego kroku. Jak zaznaczył @ JimFasarakis-Hilliard, niektórzy widzą przypadki użycia dla typu OrderedDict również w przyszłości. Myślę, że społeczność Pythona w ogóle będzie dokładnie sprawdzać, czy to wytrzyma próbę czasu i jakie będą następne kroki.

Czas na ponowne przemyślenie naszych nawyków w zakresie kodowania, aby nie przegapić możliwości otwieranych przez stabilne zamawianie:

  • Argumenty słów kluczowych i
  • (pośredni) magazyn dict

Pierwszy, ponieważ w niektórych przypadkach ułatwia wysyłanie w implementacji funkcji i metod.

Drugi, ponieważ zachęca do łatwiejszego użycia dicts jako magazyn pośredni w przetwarzaniu rurociągów.

Raymond Hettinger uprzejmie przekazał dokumentację wyjaśniającą "Słowniki Tech Behind Python 3.6"- z jego prezentacji w San Francisco Python Meetup Group 2016-DEC-08.

Być może niektóre strony o wysokim współczynniku przepełnienia w stosie i przepełnionym przepełnieniu otrzymają warianty tych informacji, a wiele odpowiedzi o wysokiej jakości będzie wymagało aktualizacji na każdą wersję.

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

Jak słusznie zauważa @ajcr: "Zachowanie porządku w tej nowej implementacji jest uważane za szczegół implementacji i nie należy na niej polegać." (z whatsnew36) nie zbieranie nitów, ale cytat został nieco pesymistyczny ;-). Jest kontynuowany jako "(może się to zmienić w przyszłości, ale pożądana jest nowa implementacja dyktowania w języku dla kilku wydań przed zmianą specyfikacji językowej w celu nadania semantyki zachowania porządku dla wszystkich obecnych i przyszłych implementacji Pythona; pomaga zachować kompatybilność wsteczną ze starszymi wersjami języka, w którym wciąż obowiązuje losowa kolejność iteracji, np. Python 3.5). "

Tak jak w niektórych językach ludzkich (np. Niemieckim), użycie kształtuje język, a teraz zostanie zadeklarowane ... w whatsnew36.

Aktualizacja 2017-12-15:

W mail do listy python-dev, Guido van Rossum oświadczył:

Zrób to tak. "Dict utrzymuje kolejność wstawiania" jest decyzją. Dzięki!

Efekt CPython w wersji 3.6, polegający na zamawianiu dyktowania, staje się teraz częścią specyfikacji językowej (i nie jest już tylko szczegółem implementacji). Ten wątek poczty również zawierał pewne wyróżniające cele projektowe collections.OrderedDict jak przypomniał Raymond Hettinger podczas dyskusji.


48
2017-09-10 10:05



Należy podkreślić ostrzeżenie na stronie "whatsnew", do której jesteś podłączony: aspekt zachowania tej nowej implementacji jest uważany za szczegół wdrożenia i nie należy na nim polegać. Nikt nie powinien zakładać, że dict type będzie respektować zamówienie reklamowe w ich kodzie. Nie jest to część definicji języka, a implementacja może się zmienić w każdej przyszłej wersji. Kontynuuj używanie OrderedDict w celu zagwarantowania zamówienia. - Alex Riley
@ajcr dziękuję za zastrzeżenie, bardzo docenione - ponieważ uśmieszki i być może utknęły w mojej odpowiedzi, te powinny wskazać, zmiana jest masywna, ale oczywiście, dostępna tylko dla CPython (implementacja referencyjna) i PyPy. Dla czegoś zupełnie innego ... Rzadko rozmawiam o szczegółach niewykonawczych przy kodowaniu instrukcji człowiek-maszyna. Gdyby to był tylko Jython ;-) ... Być może nie miałbym odwagi, by to napisać. - Dilettant
OrderedDict zdecydowanie nie zostaną zrzucone; zamiast tego stanie się cienkim opakowaniem wokół aktualnej implementacji dict (możesz dodać, że stanie się bardziej kompaktowy). Dodawanie tego fragmentu za pomocą ImportError nie jest najlepszym pomysłem ze względu na to, że wprowadzają w błąd czytelników OrderedDict nie ma sensu. - Jim Fasarakis Hilliard
@ JimFasarakis-Hilliard dziękuję za informację zwrotną. "Dość najlepsze pomysły" sprawiły, że się uśmiechnąłem - przyszłość jest często trudna do przewidzenia. Ale podoba mi się, że Twoja sugestia sprawdzi źródła, spróbuj go, a następnie odpowiednio zaktualizuj odpowiedź. Dzięki jeszcze raz. - Dilettant
W odpowiedzi na tę odpowiedź i uporządkowane dyktatury opublikowałem nowa odpowiedź. Opinia mile widziany! - Bram Vanroy


Dany słownik

e = {1:39, 4:34, 7:110, 2:87}

Sortowanie

sred = sorted(e.items(), key=lambda value: value[1])

Wynik

[(4, 34), (1, 39), (2, 87), (7, 110)]

Możesz użyć funkcji lambda, aby posortować rzeczy według wartości i zapisać je przetworzone wewnątrz zmiennej, w tym przypadku sred z mi oryginalny słownik.

Mam nadzieję, że pomaga!


41
2018-01-25 14:54





Miałem ten sam problem i rozwiązałem go tak:

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

(Ludzie, którzy odpowiadają: "Nie można sortować dyktatu" nie przeczytali pytania! "Właściwie mogę sortować klucze, ale jak mogę je sortować w oparciu o wartości?" Wyraźnie oznacza, że ​​chce on listy klucze posortowane według wartości ich wartości.)

Proszę zauważyć, że zamówienie nie jest dobrze zdefiniowane (klucze o tej samej wartości będą w dowolnej kolejności na liście wyników).


36
2017-11-18 14:19



Brakuje wartości z wyniku - Dejell
Zauważ, ż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