Як сортувати словник за значенням?


3422

У мене є словник значень, прочитаних з двох полів у базі даних: рядкового рядка та числового поля. Поле рядка унікальне, так що це ключ словника.

Я можу сортувати за ключами, але як я можу сортувати на основі значень?

Примітка. Тут я прочитав питання про переповнення стека. Як сортувати список словників за значенням словника? і, ймовірно, міг би змінити мій код, щоб мати список словників, але оскільки мені не дуже потрібен список словників, я хотів знати, чи є більш просте рішення для сортування у порядку зростання чи за убуванням.


9
Структура даних словника не має властивого порядку. Ви можете повторити його, але нічого не гарантує, що ітерація буде відповідати певному порядку. Це за задумом, тому найкращим варіантом є пробал, використовуючи структуру даних anohter для представлення.
Даїсіман

135
"sorted ()" може працювати над словниками (і повертає список відсортованих ключів), тому я думаю, що він це знає. Не знаючи його програми, абсурдно говорити комусь, що вони використовують неправильну структуру даних. Якщо швидкі пошуки - це те, що вам потрібно 90% часу, то диктант - це, мабуть, те, що ви хочете.
bobpaul

Всі три виходи (ключі, значення, обидва) для сортування словників покритий тут в ясному і короткому стилі: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman Базовий клас може бути не замовлений, але, звичайно, OrdersDict .
Тейлор Едмістон

1
У словниках Python 3.6+ зберігається порядок вставки. Це, звичайно, не те саме, що можливість їх сортування за значенням, але з іншого боку, більше не вірно говорити, що "структура даних словника не має властивого порядку".
Конрад Коцик

Відповіді:


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}

Старіший Пітон

Неможливо сортувати словник, лише отримати представлення сортованого словника. Словники за своєю суттю не впорядковані, але інших типів, таких як списки та кортежі, немає. Отже, вам потрібен упорядкований тип даних для представлення відсортованих значень, який буде списком - ймовірно, списком кортежів.

Наприклад,

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

sorted_xбуде список кортежів, відсортованих за другим елементом у кожному кортежі. dict(sorted_x) == x.

А для тих, хто бажає сортувати по клавішах замість значень:

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

У Python3, оскільки розпакування не дозволено [1], ми можемо використовувати

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

Якщо ви хочете, щоб вихід був диктатом, ви можете використовувати collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
для таймінгів на сортування різних словників за ціннісними схемами: writeonly.wordpress.com/2008/08/30/…
Грегг Лінд

164
sorted_x.reverse()дасть вам порядок зменшення (другий елемент кортежу)
saidimu apale

414
saidimu: Оскільки ми вже використовуємо sorted(), набагато ефективніше передати reverse=Trueаргумент.
rmh

121
У Python3 я використовував лямбда: sorted(d.items(), key=lambda x: x[1]). Чи буде це працювати в python 2.x?
Кейо

84
OrdersDict додано до колекцій у 2.7. Приклад сортування показано на: docs.python.org/library/…
monkut

1262

Настільки ж просто, як: sorted(dict1, key=dict1.get)

Ну, насправді можна зробити "сортування за значеннями словника". Нещодавно мені довелося це зробити в Code Golf (Питання про переповнення стека Code Golf: Частота діаграм Word ). Скорочена проблема була такою: даючи текст, підраховуйте, як часто зустрічається кожне слово, і відображайте список головних слів, відсортованих за зменшенням частоти.

Якщо ви побудуєте словник зі словами як ключі, а кількість значень кожного слова як значення, спрощене тут як:

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

тоді ви можете отримати список слів, упорядкований за частотою використання з sorted(d, key=d.get)- сортування, ітерація над клавішами словника, використовуючи кількість вхідних слів як ключ сортування.

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

Я пишу це детальне пояснення, щоб проілюструвати, що люди часто мають на увазі під «я можу легко сортувати словник за ключовими словами, але як сортувати за значенням» - і я думаю, що початковий пост намагався вирішити таке питання. І рішення - зробити своєрідний список клавіш на основі значень, як показано вище.


31
Це також добре, але key=operator.itemgetter(1)повинно бути масштабнішим за ефективністю, ніжkey=d.get
smci

3
@raylu Я спостерігаю за поведінкою "не працює" за допомогою 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 Результати змінюються щоразу, коли я запускаю код: дивно . (вибачте, не вдається отримати код для відображення належним чином)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)і for key, val in sorted_keys: print "%s: %d" % (key, val)- itemgetter створює функцію, коли вона викликається, ви не використовуєте її безпосередньо, як у вашому прикладі. І звичайна ітерація на дікт використовує ключі без значень
Ізката

18
я прийшов з майбутнього, щоб сказати вам collections.Counter, який most_commonметод, який може вас зацікавити :)
Eevee

2
@Eevee - є те, що ризик бути неправильно зрозумілим у коротких коментарях, які не є f2f. Захоплюючий ласощі: collections.Counterдодано в 2.7, який вийшов майже рівно 7 років тому! (Я тоді про це не знав - плюс я би уникнув цього в коді-гольфі з метою стислості, яка є єдиною одержимістю гри)
Нас Банов,

857

Ви можете використовувати:

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

Це сортуватиме словник за значеннями кожного запису в словнику від найменшого до найбільшого.

Щоб сортувати його у порядку зменшення, просто додайте reverse=True:

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

Вхід:

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

Вихід:

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

З того, що я бачив ( docs.python.org/2/library/… ), існує клас під назвою OrdersDict, який можна сортувати та зберігати порядок, будучи словником. З прикладів коду ви можете використовувати лямбда для сортування, але я не
перевіряв

53
Я вважаю за краще key=lambda (k, v): vособисто
Клавдіу

35
@Claudiu Мені також подобається цей (k, v)синтаксис, але він недоступний у Python 3, де було видалено розпакування параметрів кортежу .
Боб Штейн

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

3
Ні. Створення дикту з відсортованого списку кортежів вбиває замовлення знову ...
Жан-Франсуа Фабре

233

Дикти не можна сортувати, але ви можете створити з них відсортований список.

Сортований список значень dict:

sorted(d.values())

Список пар (ключ, значення), відсортований за значенням:

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

У якому порядку розміщуються ключі з однаковим значенням? Я сортував список спочатку за ключами, потім за значеннями, але порядок клавіш з однаковим значенням не залишається.
SabreWolfy

1
Дикти тепер можна сортувати, починаючи з CPython 3.6 та всіх інших реалізацій Python, починаючи з 3.7
Борис

161

Нещодавно в Python 2.7 у нас з'явився новий OrdersDict тип, який запам'ятовує порядок додавання елементів.

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

Щоб створити новий упорядкований словник з оригіналу, сортуючи за значеннями:

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

OrdersDict поводиться як звичайний дикт:

>>> 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
Про це не йдеться - йдеться не про підтримку порядку ключів, а про "сортування за значенням"
Нас Банов

10
@Nas Banov: це НЕ сортування за ключем. це сортування за порядком, ми створюємо елементи. у нашому випадку ми сортуємо за значенням. на жаль, 3-елементний дикт був, на жаль, обраний, тому порядок був однаковим, коли сортували голос за значенням і ключем, тому я розширив зразок дікта.
mykhal

sorted(d.items(), key=lambda x: x[1])Чи можете ви пояснити, що xозначає, чому це може знадобитися x[1]лямбда? Чому цього не може бути x[0]? Дуже дякую!
JZAU

1
@Boern d.items()повертає список подібних контейнерів (key, value)кортежів. [0]отримує доступ до першого елемента кортежа - ключа - і [1]отримує доступ до другого елемента - значення.
BallpointBen

2
Примітка: В 3,6 (як деталь реалізації CPython / PyPy) і в 3,7 ( в якості гарантії на мові Python), простий dictє вставка замовляється, так що ви можете просто замінити OrderedDictз dictдля коду , що працює на сучасному мові Python. OrderedDictнасправді більше не потрібен, якщо вам не потрібно буде переставляти порядок існуючого dictmove_to_end/ popitem) або не потрібно проводити порівняння рівності, щоб залежно від порядку. Він використовує набагато більше пам'яті, ніж звичайний dict, тому, якщо можете, dictце шлях.
ShadowRanger

104

ОНОВЛЕННЯ: 5 грудня 2015 року за допомогою Python 3.5

Хоча я визнав прийняту відповідь корисною, я також був здивований, що вона не була оновлена, щоб посилатись на OrdersDict зі стандартного модуля колекцій бібліотек як життєздатну сучасну альтернативу, розроблену для вирішення саме такого типу проблеми.

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

Офіційна документація OrdersDict також пропонує дуже подібний приклад, але за допомогою функції лямбда використовується сортування:

# 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

Приблизно те саме, що відповідь Хенка Гей :

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

Або дещо оптимізовано, як запропонував Джон Фугі:

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

9
..і як і у відповіді Хенка Гей, вам не потрібні квадратні дужки. sorted () з радістю візьме будь-який ітерабельний, наприклад, вираз генератора.
Джон Фухі

Можливо, вам знадобиться поміняти місцями (значення, ключ) кортежними елементами, щоб закінчити (ключ, значення). Потім потрібно інше розуміння списку. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale

ні, краще залишити квадратні дужки, тому що sortedдоведеться все-таки відновити список, і відбудова з gencomp буде швидшою. Добре для кодового гольфу, погано для швидкості. Тримайте потворну ([])версію.
Жан-Франсуа Фабре

75

Часто може бути дуже зручно використовувати nametuple . Наприклад, у вас є словник 'name' як клавіш і 'score' як значення, і ви хочете сортувати за 'score':

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

сортування з найнижчим балом спочатку:

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

сортування з найвищим балом першим:

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

Тепер ви можете отримати ім'я та рахунок, скажімо, другий найкращий гравець (індекс = 1) дуже піфонічно такий:

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

Як я міг перетворити його назад у словник?
rowana

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

72

Станом на Python 3.6 вбудований дикт буде замовлений

Хороша новина, тому оригінальний випадок використання ОП картування пар, отриманих із бази даних, з унікальними ідентифікаторами рядків як ключами та числовими значеннями як значеннями у вбудований Python v3.6 + dict, тепер повинен поважати порядок вставки.

Якщо сказати отримані два вирази таблиці стовпців із запиту бази даних, наприклад:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

буде зберігатися у двох кортежах Python, k_seq і v_seq (вирівнюються за числовим індексом і з однаковою довжиною курсу), тоді:

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

Дозволити виводити пізніше як:

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

У цьому випадку поступається (для нового вбудованого протоколу Python 3.6+!):

foo 0
bar 1
baz 42

в такому ж порядку впорядкованості за значенням v.

Там, де в моїй машині встановлено Python 3.5, він наразі дає:

bar 1
foo 0
baz 42

Деталі:

Як запропонував у 2012 році Реймонд Хеттінгер (пор. Пошта на python-dev з темою "Більш компактні словники з більш швидкою ітерацією" ), а тепер (у 2016 році) оголошений у пошті Віктора Стіннера до python-dev з темою " Дік Python 3.6 стає компактний і отримує приватну версію, а ключові слова впорядковуються " завдяки виправленню / реалізації випуску 27350 " Компактний і впорядкований dict " в Python 3.6 ми тепер зможемо використовувати вбудований dict для підтримки порядку вставки !!

Сподіваємось, це призведе до виконання тонкого шару впорядкованого порядку як першого кроку. Як зазначає @ JimFasarakis-Hilliard, деякі бачать випадки використання для типу OrdersDict також у майбутньому. Я думаю, що спільнота Python взагалі ретельно перевірить, чи це витримає перевірку часу та які будуть наступні кроки.

Час переосмислити свої звички кодування, щоб не упустити можливості, відкриті стабільним замовленням:

  • Аргументи ключових слів і
  • (проміжне) зберігання dict

Перший тому, що в деяких випадках полегшує відправлення при здійсненні функцій та методів.

Другий, оскільки заохочує легше використовувати dicts як проміжне зберігання в обробці трубопроводів.

Реймонд Хеттінгер люб’язно надав документацію, що пояснює " Техніку за словниками Python 3.6 " - з презентації групи "Сан-Франциско Python Meetup Group 2016-DEC-08".

І, можливо, цілком багато оформлених сторінок запитань та відповідей на Stack Overflow отримають варіанти цієї інформації, і багато високоякісних відповідей також потребуватимуть оновлення версії.

Caveat Emptor (але також див. Нижче оновлення 2017-12-15):

Як справедливо зазначає @ajcr: "Аспект, що зберігає замовлення, у цій новій реалізації вважається детальною частиною реалізації, і на неї не слід покладатися". (з Whatsnew36 ) не збирав ніт, але цитування було скорочено песимістично ;-). Це продовжується як "(це може змінитися в майбутньому, але бажано, щоб ця нова диктовка була реалізована мовою протягом декількох випусків, перш ніж змінити специфікацію мови на мандат, що зберігає порядок, для всіх поточних та майбутніх реалізацій Python; це також допомагає зберегти сумісність назад із старими версіями мови, де досі діє випадковий порядок ітерації, наприклад, Python 3.5). "

Так, як і в деяких людських мовах (наприклад, німецькій), вживання формує мову, і воля тепер була оголошена ... у Whatsnew36 .

Оновлення 2017-12-15:

У пошті до списку пітон-розробок Гвідо ван Россум заявив:

Зробіть так. "Дикт зберігає порядок вставки" є постановою. Дякую!

Отже, побічний ефект впорядкування вставки дикту версії 3.6 CPython тепер стає частиною мовної специфікації (і вже не лише деталі реалізації). Цей поштовий потік також виявив деякі відмітні цілі дизайну, про які collections.OrderedDictнагадав Реймонд Хеттінгер під час обговорення.


15
Слід підкреслити попередження на сторінці "Whatsnew", на яку ви посилаєтесь: аспект збереження порядку в цій новій реалізації розглядається як деталь реалізації, і на неї не слід покладатися . Ніхто не повинен припускати, що dictтип буде дотримуватися порядку вставки у своєму коді. Це не є частиною визначення мови, і реалізація може змінитися в будь-якому майбутньому випуску. Продовжуйте використовувати OrderedDictгарантійне замовлення.
Алекс Райлі

@ajcr спасибі за застереження, дуже вдячний - оскільки смайлики та, можливо, були вкладені у мою відповідь, це повинно вказати, зміна є масовою, але, звичайно, доступна лише для CPython (реалізація посилань) та PyPy. Щось зовсім інше ... Я рідко розмовляю з деталями нереалізації, кодуючи інструкції man-machine. Якби це був тільки Jython ;-) ... я б, можливо, не мав сміливості це написати.
Дилетант

OrderedDictточно не скинеться; натомість він стане тонкою обгорткою навколо поточної реалізації диктату (тож ви можете додати, що він також стане більш компактним). Додавання цього фрагмента ImportErrorне зовсім найкраща ідея, оскільки він вводить в оману читачів, які OrderedDictне мають користі.
Дімітріс Фасаракіс Хілліард

@ JimFasarakis-Hilliard дякую за відгук. "Найкращі ідеї" змусили мене посміхнутися - майбутнє часто важко передбачити. Але мені подобається, що ваша пропозиція перевірить джерела, спробує її, а потім оновить відповідь відповідно. Знову дякую.
Дилетант

8
@AlexRiley Цей застереження вже не є точним. Python3.7 гарантує впорядковані словники.
Герріт

42

У мене була така ж проблема, і я вирішив її так:

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

(Люди, які відповідають "Неможливо сортувати дік", не читали питання! Насправді "я можу сортувати за ключами, але як я можу сортувати на основі значень?", Очевидно, означає, що він хоче список клавіші відсортовані відповідно до значення їх значень.)

Зауважте, що порядок недостатньо визначений (клавіші з однаковим значенням будуть у довільному порядку у списку вихідних даних).


1
Вам не вистачає значення в результаті
Dejell

Зауважте, що ви обидва ітератуєте словник та отримуєте значення за їх ключем, тому ефективність роботи не є оптимальним рішенням.
Рон Кляйн

1
@Dejell: як каже дописувач, він трактує питання як "чи можу я отримати список клавіш, відсортований відповідно до значень". Нам не потрібні значення в результаті, ми маємо їх у словнику.
Макс

36

Якщо значення є числовими, ви також можете використовувати Counterз колекцій .

from collections import Counter

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

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

що робити, якщо ви словник >>> x = {'hello': 1, 'python': 5, 'world': 300}
Джеймс Сапам

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()дає [('world', 300), ('python', 5), ('hello', 1)]. Це фактично працює для будь-якого типу сортуваного значення (хоча багато інших операцій Counter вимагають, щоб значення були порівнянні з ints).
lvc

34

У Python 2.7 просто виконайте такі дії:

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

Скопіюйте-вставте з: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Насолоджуйтесь ;-)


25

Це код:

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

Ось результати:

Оригінал

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

Ранг

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

Спробуйте наступний підхід. Давайте визначимо словник, який називається мій суд, з такими даними:

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

Якби хотіли сортувати словник за клавішами, можна зробити щось на кшталт:

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

Це має повернути такий результат:

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

З іншого боку, якби хотіли сортувати словник за значенням (про що йдеться у запитанні), можна зробити наступне:

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

Результат цієї команди (сортування словника за значенням) повинен повертати наступне:

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

Дивовижно! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):дозволяє сортувати за підрозділом
Andomar

це дає мені синтаксичну помилку біля лямбда в Python3
Elahi

21

Починаючи з Python 3.6, dictоб’єкти тепер упорядковуються в порядку вставки. Офіційно це в специфікаціях 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}

До цього вам довелося користуватися OrderedDict.

Документація Python 3.7 говорить:

Змінено у версії 3.7: Порядок словника гарантується порядком вставки. Така поведінка була деталізацією реалізації CPython від 3.6.


працює чудово! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))для DESC
vizyourdata

20

Ви також можете створити "перевернутий індекс"

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

Тепер ваша обернена має значення; кожне значення має перелік застосовних ключів.

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

19

Ви можете використовувати колекції.Каунт . Зверніть увагу, це буде працювати як для числових, так і для нечислових значень.

>>> 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
Чим це відрізняється від відповіді Івана Саса ?
Пітер Мортенсен

15

Ви можете використовувати пропускний dict, який є словником, який постійно сортується за значенням.

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

Якщо ви використовуєте keys(), values()або items()тоді ви будете повторювати в упорядкованому порядку за значенням.

Він реалізований за допомогою структури даних пропускного списку .


чи можемо ми змінити порядок сортування, зараз він змінюється, але я хочу зменшуватися.
Сулеман Елахі

afaik, вам доведеться заперечувати свої значення, щоб скасувати замовлення
малте

Нічого, я думаю, що так думаю ... дякую.
Сулеман Елахі

14

Ви також можете користувальницьку функцію, яку можна передати клавіші.

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
Питання було: сортувати за значенням, а не за ключами ... Мені подобається бачити функцію. Ви можете імпортувати колекції та звичайно використовувати сортовані (data.values ​​())
Ремі

10

Як вказував Dilettant , Python 3.6 тепер буде підтримувати порядок ! Я думав, що поділюсь функцією, яку я написав, що полегшує сортування ітерабельного (кортеж, список, дікта). В останньому випадку ви можете сортувати або за ключами, або за значеннями, і це може враховувати числове порівняння. Тільки для> = 3,6!

Якщо ви спробуєте використати сортування на ітерабелі, який містить, наприклад, рядки, а також ints, сортування () не вдасться. Звичайно, ви можете примусити порівняння рядків з str (). Однак у деяких випадках потрібно зробити фактичне числове порівняння там, де 12він менший ніж 20(що не відбувається у порівнянні рядків). Тому я придумав наступне. Якщо потрібно чітке числове порівняння, ви можете використовувати прапор, num_as_numякий намагатиметься зробити явне числове сортування, намагаючись перетворити всі значення в плавці. Якщо це вдасться, воно здійснить числове сортування, інакше вдасться до порівняння рядків.

Зауваження щодо вдосконалення або запитів просимо вітаються.

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

Ось рішення за допомогою zip on d.values()іd.keys() . Кілька рядків внизу цього посилання (на об'єктах подання словника):

Це дозволяє створити (значення, ключ) пар за допомогою zip (): пар = zip (d.values ​​(), d.keys ()).

Тож ми можемо зробити наступне:

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

Звичайно, пам’ятайте, що вам потрібно користуватися, OrderedDictоскільки звичайні словники Python не дотримуються початкового порядку.

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

Якщо у вас немає Python 2.7 або новішої версії, найкраще, що ви можете зробити, це повторити значення у функції генератора. (Існує OrderedDictдля 2.4 і 2.6 тут , але

а) Я не знаю про те, наскільки добре це працює

і

б) Ви, звичайно, повинні завантажити та встановити його. Якщо у вас немає адміністративного доступу, я боюсь, що варіант не доступний.)


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

Ви також можете роздрукувати кожне значення

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

Будь ласка, не забудьте видалити дужки після друку, якщо не використовується Python 3.0 або вище


звичайні словники Python не дотримуються початкового порядку - як і в Python 3.7.
Герріт

7

Використовуйте ValueSortedDict з 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

Це працює в 3.1.x:

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

6

Щойно вивчив відповідну майстерність від Python для всіх .

Ви можете використовувати тимчасовий список, який допоможе вам сортувати словник:

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

Якщо ви хочете сортувати список у порядку зменшення, просто змініть початковий рядок сортування на:

tmp = sorted(tmp, reverse=True)

Використовуючи розуміння списку, одним лайнером буде:

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

Вибірка зразка:

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

це сортування за ключами, а не за значеннями.
Рубель

Якщо ви хочете роздрукувати його у початковому форматі, вам слід зробити: print ([(k, v) for v, k у сортованому ([(v, k) для k, v у d.items ()])]). Вихід: [('апельсин', 1.0), ('яблуко', 500.1), ('ананас', 789.0), ('банан', 1500.2)]. З [(k, v) для v, k у сортованому ([(v, k) для k, v в d.items ()], зворотній = True)] вихід: [('banana', 1500.2), ('ананас', 789.0), ('яблуко', 500.1), ('апельсин', 1.0)]
Гермес Моралес

5

Ітерація через дікт і сортуйте його за значеннями у порядку зменшення:

$ 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

Якщо ваші значення - цілі числа, а ви використовуєте Python 2.7 або новіші, ви можете використовувати collections.Counterзамість них dict. most_commonМетод дасть вам все елементи, впорядковані за значенням.


5

Для повноти я розміщую рішення за допомогою heapq . Зауважте, цей метод буде працювати як для числових, так і для нечислових значень

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

Через вимоги зберегти зворотну сумісність зі старими версіями Python я думаю, що рішення OrdersDict дуже нерозумно. Вам потрібно щось, що працює з Python 2.7 та старішими версіями.

Але рішення про колекції, згадане в іншій відповіді, є абсолютно чудовим, тому що ви перенавчаєте зв’язок між ключем і значенням, що у випадку словників є надзвичайно важливим.

Я не згоден з вибором номер один, поданим в іншій відповіді, тому що він викидає ключі.

Я використовував рішення, згадане вище (код, показаний нижче) і зберіг доступ до ключів і значень, і в моєму випадку впорядкування було на значення, але важливим було впорядкування ключів після впорядкування значень.

from collections import Counter

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


>> [('python', 5), ('world', 3), ('hello', 1)]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.