Python 3 сортує дикт за його значеннями


79

Єдині методи, які я знайшов, працюють для python2 або повертають лише список кортежів.

Чи можна сортувати словник, наприклад {"aa": 3, "bb": 4, "cc": 2, "dd": 1}, за його значеннями?

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

bb 4
aa 3
cc 2
dd 1

І після сортування я хочу зберегти його у текстовому файлі.

Відповіді:


120

itemgetter(див. інші відповіді) є (наскільки мені відомо) ефективнішим для великих словників, але для загального випадку я вважаю, що він d.getвиграє. І це не вимагає додаткових витрат import.

>>> d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
>>> for k in sorted(d, key=d.get, reverse=True):
...     k, d[k]
...
('bb', 4)
('aa', 3)
('cc', 2)
('dd', 1)

Зверніть увагу , що в якості альтернативи ви можете встановити в d.__getitem__якості keyфункції , яка може забезпечити невеликий приріст продуктивності по порівнянні з d.get.


1
Не могли б ви пояснити | розширити синтаксис у рядку 2? Я просто вивчаю Python 3 і хотів би зрозуміти цей.
Серж

2
Звичайно, але було б простіше, якби я знав те, чого ти не розумієш. [x for x in iterable]це розуміння списку Python (google), яке є дуже поширеним та ефективним у Python для створення списків. (k, d[k])є двоелементним набором, другий елемент ( d[k]) - значення зі словника. sorted()- це вбудована функція, яка повертає ключі словника, відсортовані за значеннями. Використовуючи key=d.getце, ключ моєї відповіді, про який нетривіально знати. Знання вбудованих функцій є дуже важливим. Сподіваюся, це допомогло.
SieeberthAdam

Дякую! [x for x in iterable]«Список розуміння» є те , що відсутня в інтро курсі. Зараз читаю про це (важко було знайти, не знаючи назви).
Серж

29
from collections import OrderedDict
from operator import itemgetter    

d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
print(OrderedDict(sorted(d.items(), key = itemgetter(1), reverse = True)))

відбитки

OrderedDict([('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)])

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

from operator import itemgetter  

d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
for key, value in sorted(d.items(), key = itemgetter(1), reverse = True):
    print(key, value)

який друкує

bb 4
aa 3
cc 2
dd 1

Спасибі за вашу допомогу. Я думав, що одним із рішень буде щось подібне до цього.

1
dictзберігає порядок вставки зараз, тому немає жодних причин для використанняOrderedDict
Борис

2
Я можу подумати з двох причин, по-перше, це чітко вказує на те, що ви дбаєте про порядок, по-друге, хтось може запустити ваш код на старішому інтерпретаторі, а якщо мовчки неправильно поводиться, це не є хорошим результатом.
plugwash

17

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

{k: d[k] for k in sorted(d, key=d.get, reverse=True)}
# {'b': 4, 'a': 3, 'c': 2, 'd': 1}

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

{k: d[k] for k in sorted(d, key=d.get)}
# {'d': 1, 'c': 2, 'a': 3, 'b': 4}

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

{k: d[k] for k in sorted(d)}
# {'a': 3, 'b': 4, 'c': 2, 'd': 1}

Це працює на CPython 3.6+ та будь-якій реалізації Python 3.7+, оскільки словники зберігають порядок вставки.


12

Інший спосіб - використовувати лямбда-вираз. Залежно від версії інтерпретатора та від того, чи хочете ви створити відсортований словник або відсортовані кортежі ключ-значення (як це робить OP), це може бути навіть швидше прийнятої відповіді.

d = {'aa': 3, 'bb': 4, 'cc': 2, 'dd': 1}
s = sorted(d.items(), key=lambda x: x[1], reverse=True)

for k, v in s:
    print(k, v)

1
Поки ваш код працює, я не думаю, що словники гарантовано повертатимуть елементи в тому самому порядку, як додано.
Іван

2
@Ivan Дякую - я видалив зайве використання dict () тут, хоча в CPython 3.6+ dict зберігає порядок, і це, швидше за все, стане мовною особливістю найближчим часом ( docs.python.org/3 /whatsnew/3.6.html )
Беде Константинід

Дякую, цікаво знати. Крім того - в кінці ви можете просто зробити print(s)замість петлі :)
Іван

1
dicts зберігати порядок у всіх Pythons, починаючи з 3.7
Борис

1
насправді це менше 10%, я отримую 54 мс проти 57,3 мс на Python 3.8.6 зі словником 100 000 елементів, але технічно все одно повільніше. Я думаю, вам слід їх видалити, це не варта оптимізація.
Борис

10

Для сортування словника ми могли б використовувати модуль оператора. Ось документація до модуля оператора.

import operator                             #Importing operator module
dc =  {"aa": 3, "bb": 4, "cc": 2, "dd": 1}  #Dictionary to be sorted

dc_sort = sorted(dc.items(),key = operator.itemgetter(1),reverse = True)
print dc_sort

Вихідна послідовність буде відсортованим списком:

[('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)]

Якщо ми хочемо сортувати за клавішами, ми можемо скористатися

dc_sort = sorted(dc.items(),key = operator.itemgetter(0),reverse = True)

Вихідна послідовність буде такою:

[('dd', 1), ('cc', 2), ('bb', 4), ('aa', 3)]

Відповідь Пола Дрейпера вже використовується Operator ... просто не імпортується вся бібліотека
Сальваторе Косентіно

0

Щоб відсортувати словник і продовжувати функціонувати як словник, ви можете скористатися OrderedDict зі стандартної бібліотеки.

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


dictзберігає порядок вставки зараз, тому немає жодних причин для використанняOrderedDict
Борис
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.