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


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

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

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


2938
2018-03-05 00:49


походження


Структурна структура даних не має притаманного замовлення. Ви можете прослідкувати за нею, але немає нічого, щоб гарантувати, що ітерація буде виконувати будь-який конкретний порядок. Це за проектом, тому найкращим ставленням є, мабуть, використання структури даних anohter для представлення. - Daishiman
"Сортований ()" може працювати на словниках (і повертає список сортованих клавіш), тому я думаю, що він це обізнаний. Не знаючи своєї програми, це абсурдно сказати комусь, що вони використовують неправильну структуру даних. Якщо швидкий пошук є тим, що потрібно 90% часу, то напевно, що це дикт, що ви хочете. - bobpaul
Для тих, хто вважає, що це дублікат stackoverflow.com/questions/72899/... , це питання позначено як дублікат цього запитання. - Marcin
Якщо це можливо, виконайте інсталяцію NumPy Series з словника та сортувати його за допомогою pandas.Series.order - Dror
Усі три виходи (ключі, значення, обидва) для сортування словників розглядаються тут ясним і стислим стилем: stackoverflow.com/questions/16772071/sort-dict-by-value-python - JStrahl


Відповіді:


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

Наприклад,

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_by_value = sorted(x.items(), key=lambda kv: kv[1])

3554
2018-03-05 00:59



для синхронізації різних сортування словників за схемою цінності: writeonly.wordpress.com/2008/08/30/... - Gregg Lind
sorted_x.reverse() дасть вам спадне замовлення (за другим елементом кортежу) - saidimu apale
sakimu: Оскільки ми вже використовуємо sorted(), набагато ефективніше пройти в reverse=True аргумент - rmh
У python3 я використовував лямбду: sorted(d.items(), key=lambda x: x[1]). Чи буде ця робота в python 2.x? - Keyo
OrderedDict додано до колекцій у 2.7. Приклад сортування показано на сторінці: docs.python.org/library/... - monkut


Такий простий, як: sorted(dict1, key=dict1.get)

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

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

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]

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


969
2017-07-05 08:01



Це теж добре, але key=operator.itemgetter(1) повинна бути більш масштабована для ефективності, ніж key=d.get - smci
Вам спочатку потрібно: імпортувати колекції # для використання defaultdict - rjurney
@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
@ блі sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True) і for key, val in sorted_keys: print "%s: %d" % (key, val) - itemgetter створює функцію, коли вона викликається, ви не використовуєте її прямо як у вашому прикладі. А звичайна ітерація на dict використовує ключі без значень - Izkata
Я прийшов з майбутнього, щоб розповісти вам collections.Counter, який має most_common метод, який може вас зацікавити :) - Eevee


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

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

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


607
2018-02-13 16:33



+1 Для того, щоб бути найчистішим рішенням. Однак це не сортує словник (хеш-таблиця, неможливо), а скоріше, він повертає упорядкований список (key, value) кортежі - Keyo
@Keyo Я новачок в python і зіткнувся з необхідністю сортувати словник. І я хочу переконатися, що я добре вас зрозумів: неможливо використати лямбда для сортування словника, чи не так? - lv10
Я б вважав за краще key=lambda (k, v): v особисто - Claudiu
@ Клауді мені це подобається (k, v) синтаксис, але він недоступний в Python 3, де розпакування параметрів кортежу був вилучений - Bob Stein
@Nyxynyx Просто додайте reverse=True всередині сортованого біту (тобто sorted(a.items(), key=lambda x: x[1], reverse=True)) - Mathime


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

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

sorted(d.values())

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

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

165
2018-03-05 01:05



+1: сортовані (d.values ​​()) легше читати / розуміти, ніж відсортовані Nas (dict1, key = dict1.get), а отже, і більше Pythonic. Про читабельність, будь ласка, також розгляньте мій namedtuple пропозиція - Remi
Який порядок - це ключі з тим же значенням? Я спочатку сортував список за допомогою клавіш, потім за значеннями, але порядок клавіш з тим самим значенням не залишається. - SabreWolfy
@Remi, це два різні речі! sorted(d.values()) повертає відсортований список цінності з словника, де sorted(d, key=d.get) повертає список ключі, відсортовані в порядку цінностей! Шлях відрізняється. Якщо ви не бачите необхідності останнього, прочитайте мою посаду вище для прикладу "реального життя" - Nas Banov


У недавньому Python 2.7 ми маємо нове OrderedDict тип, який запам'ятовує порядок додавання елементів.

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

OrderedDict веде себе як нормальний дикт:

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



Це не питання, про яке йдеться - це не про збереження порядку ключів, а про "сортування за значенням" - Nas Banov
@Нас Банов: це НЕ сортується ключем. це сортування в порядку, ми створюємо предмети. у нашому випадку ми сортуємо за значенням. на жаль, 3-елементний дикт був, на жаль, вибраний таким чином, замовлення був таким же, коли сортували VOT за значенням та ключем, тому я розширив зразок dict. - mykhal
sorted(d.items(), key=lambda x: x[1]) Ви можете пояснити, що xозначає, чому це може зайняти x[1] лямбда? Чому це не може бути x[0]? Велике спасибі! - JZAU
@ jie d.items() повертає список пар ключ / значення зі словника та x є елементом цього кортежу. x[0] буде ключовим і x[1] буде значенням. Оскільки ми маємо намір відсортувати значення, ми передаємо x[1] до лямбда - CadentOrange
@ Бурнал d.items() повертає список як контейнер з (key, value) кортежі [0] звертається до першого елемента кортежу - ключ - і [1] звертається до другого елементу - значення. - BallpointBen


ОНОВЛЕННЯ: 5 ГРУДНЯ 2015 РОКУ, використовуючи Python 3.5

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

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

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

# 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





Зазвичай це дуже зручно використовувати namedtuple. Наприклад, у вас є словник "ім'я" як ключі і "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)

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

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

64
2017-08-30 00:30



Як мені повернутися до словника? - rowana
as_list = [Player (v, k) для (k, v) в d.items ()] as_dict = dict ((p.name, p.score) для p в as_list) - Remi


Дуже така ж, як відповідь Ханк Гей;


    відсортовано ([(значення, ключ) для (ключ, значення) у mydict.items ()])

Або трохи оптимізовано, як запропонував Джон Фоухі;


    відсортовано ((значення, ключ) для (ключ, значення) у mydict.items ())


57
2018-03-05 01:06



.. і як відповідає Хенк Гей, вам не потрібні квадратні дужки. відсортовані () щасливо візьмуть будь-яке ітерабельність, наприклад, вираз генератора. - John Fouhy
Можливо, вам доведеться поміняти елементи кортежу (значення, ключ), щоб закінчити (ключ, значення). Потрібно ще одне усвідомлення списку. [(key, value) for (value, key) in sorted_list_of_tuples] - saidimu apale
ні, краще залишити квадратні дужки, тому що sorted в будь-якому випадку доведеться перебудувати список, і відновлення від gencomp буде швидшим. Добре для кодування гольфу, погано для швидкості. Тримай некрасиво ([]) версія - Jean-François Fabre


Щодо Python 3.6 вбудований dict буде замовлений

Хороші новини, тому оригінальний варіант користування ОП парі відображення, отриманих з бази даних з унікальними ідентифікаторами рядка, як ключі та числові значення, як значення вбудованого 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+ вбудований dict!):

foo 0
bar 1
baz 42

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

Де в Python 3.5 встановити на моєму комп'ютері, він в даний час дає:

bar 1
foo 0
baz 42

Подробиці:

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

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

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

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

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

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

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

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

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

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

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

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

В пошта до списку python-dev, Гвідо ван Россум заявив:

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

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


48
2017-09-10 10:05



Потрібно підкреслити попередження на сторінці "whatsnew", з яким ви зв'язали. консервативний аспект цієї нової реалізації розглядається деталі реалізації, і на нього не слід покладатися. Ніхто не повинен припускати, що dict type буде поважати порядок вставки в їх коді. Це не є частиною визначення мови, і реалізація може змінюватися в будь-якому майбутньому випуску. Продовжити використання OrderedDict гарантувати порядок. - Alex Riley
@ajcr спасибі за застереження, дуже вдячні - як посмішки, і, можливо, були зшиті в мою відповідь, слід зазначити, що зміна масивна, але, звичайно, доступна лише для CPython (reference implementation) і PyPy. Для чогось зовсім іншого ... Я рідко розмовляю з деталями невиконання, кодуючи інструкції man-machine. Якщо б це було тільки Джистоном ;-) ... Я, можливо, не мав сміливості писати це. - Dilettant
OrderedDict безумовно, не буде скинутий; Замість цього він стане тонкою обгорткою навколо поточної реалізації dict (так що ви можете додати, що це також буде більш компактним). Додавання цього фрагмента з ImportError це не зовсім краща ідея через те, що це вводить в оману читачів OrderedDict не має ніякого користі. - Jim Fasarakis Hilliard
@ Джим Фасаракіс-Хіліард дякую за відгук. "Дуже кращі ідеї" змусили мене посміхнутися - майбутнє часто важко передбачити. Але мені подобається ваша пропозиція буде перевіряти джерела, спробувати це, а потім оновити відповідь відповідним чином. Знову дякую. - Dilettant
У відповідь на цю відповідь, і структуровані dicts, я опублікував нова відповідь. Зворотній зв'язок! - Bram Vanroy


Даний словник

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

Сортування

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

Результат

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

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

Надія, що допомагає!


41
2018-01-25 14:54





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

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

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

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


36
2017-11-18 14:19



Ви не маєте значення в результаті - Dejell
Зауважте, що ви одночасно повторюєте словник та отримуєте цінності за ключовими словами, тому продуктивність це не є оптимальним рішенням. - Ron Klein