Как отсортировать словарь по значению?

2543
голосов

У меня есть словарь значений, считанных из двух полей в базе данных: поле строки и числовое поле. Строковое поле уникально, поэтому это ключ словаря.

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

Примечание. Я прочитал вопрос о переполнении стека Как отсортировать список словарей по значениям словаря в Python? и, возможно, может изменить мой код, чтобы иметь список словарей, но поскольку мне действительно не нужен список словарей, я хотел бы знать, есть ли более простое решение.

задан Gern Blanston 05 марта '09 в 3:49
источник

38 ответов

  • 1
  • 2
3088
голосов

Невозможно отсортировать dict, только чтобы получить представление сортировки dict. Дикты по своей сути беспартийны, но другие типы, такие как списки и кортежи, не являются. Поэтому вам нужен упорядоченный тип данных для представления отсортированных значений, которые будут списком, возможно, списком кортежей.

Например,

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))
ответ дан Devin Jeanpierre 05 марта '09 в 3:59
источник
875
голосов

Проще, чем: sorted(dict1, key=dict1.get)

Ну, на самом деле можно сделать "сортировку по значениям словаря". Недавно мне пришлось сделать это в Code Golf (вопрос 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]

Я пишу это подробное объяснение, чтобы проиллюстрировать, что люди часто подразумевают под "Я могу легко сортировать словарь по ключевым словам, но как я сортирую по значению" - и я думаю, что ОП пытался решить такую ​​проблему. И решение состоит в том, чтобы выполнить сортировку списка ключей на основе значений, как показано выше.

ответ дан Nas Banov 05 июля '10 в 11:01
источник
516
голосов

Вы можете использовать:

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

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

ответ дан Mark 13 февр. '10 в 19:33
источник
143
голосов

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

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

sorted(d.values())

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

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))
ответ дан Roberto Bonvallet 05 марта '09 в 4:05
источник
109
голосов

В последнем 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 ведет себя как обычный 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)])
ответ дан mykhal 05 июля '10 в 5:50
источник
59
голосов

ОБНОВЛЕНИЕ: 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)])
ответ дан arcseldon 05 дек. '15 в 12:46
источник
54
голосов

Часто бывает очень удобно использовать namedtuple. Например, у вас есть словарь "имя" в качестве ключей и "оценка" в качестве значений, и вы хотите сортировать по "оценке":

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
ответ дан Remi 30 авг. '11 в 3:30
источник
47
голосов

В значительной степени то же, что и ответ Хэнк Гей;


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

Или немного оптимизирован, как предложил Джон Фухи;


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

ответ дан user26294 05 марта '09 в 4:06
источник
31
голос

Данный словарь

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

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

Надеюсь, что это поможет!

ответ дан Bishop 25 янв. '16 в 17:54
источник
29
голосов

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

copy-paste из: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

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

ответ дан sweetdream 22 авг. '13 в 11:38
источник
26
голосов

Начиная с Python 3.6 встроенный dict будет упорядочен

Хорошие новости, поэтому исходный пример использования OP-карт, полученных из базы данных с уникальными идентификаторами строк в виде ключей и числовых значений в виде значений во встроенный 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 dict становится компактным и получает личную версию, а ключевые слова упорядочиваются" из-за исправления/реализации проблемы 27350 "Компактный и упорядоченный диктов" в Python 3.6 мы теперь сможем используйте встроенный dict для сохранения порядка вставки!

Надеемся, это приведет к реализации тонкого слоя OrderedDict в качестве первого шага. Как указал @JimFasarakis-Hilliard, некоторые из них видят также случаи использования типа OrderedDict в будущем. Я думаю, что сообщество Python в целом будет тщательно проверять, если это выдержит испытание временем и какие будут следующие шаги.

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

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

Первое, потому что в некоторых случаях облегчает отправку в реализации функций и методов.

Второй, поскольку он рекомендует более легко использовать dict в качестве промежуточного хранилища в обрабатывающих конвейерах.

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

И, может быть, некоторые страницы с высоким разрешением и ответы на вопросы Qaru получат варианты этой информации, и многие высококачественные ответы потребуют обновления для каждой версии.

Caveat Emptor (но также см. ниже обновление 2017-12-15):

Как @ajcr справедливо отмечает: "Приоритет сохранения этой новой реализации рассматривается как деталь реализации и на нее нельзя положиться". (из whatsnew36) не nit picking, , но цитата была отрезана немного пессимистично;-). Он продолжается как "(это может измениться в будущем, но желательно, чтобы эта новая реализация dict на языке для нескольких выпусков до изменения спецификации языка для мандатной семантики сохранения порядка для всех текущих и будущих реализаций Python, это также помогает сохранить обратную совместимость со старыми версиями языка, где по-прежнему действует случайный порядок итераций, например Python 3.5).

Так, как и на некоторых человеческих языках (например, на немецком языке), использование формирует язык, и теперь будет объявлена ​​воля... в whatsnew36.

Обновление 2017-12-15:

В mail в список python-dev, Guido van Rossum заявил:

Сделайте так. "Dict сохраняет порядок вставки" - это решение. Благодарю!

Итак, версия 3.6 CPython побочный эффект упорядочивания вставки dict теперь становится частью спецификации языка (и не только является только деталью реализации). Этот почтовый поток также выявил некоторые отличительные цели дизайна для collections.OrderedDict, как напомнил Раймонд Хеттингер во время обсуждения.

ответ дан Dilettant 10 сент. '16 в 13:05
источник
25
голосов

У меня была та же проблема, и я решил это следующим образом:

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

(Люди, которые отвечают "Невозможно сортировать дикт", не читали вопрос! На самом деле, "я могу сортировать по ключам, но как я могу сортировать на основе значений?" явно означает, что он хочет список ключей, отсортированных по значению их значений.)

Обратите внимание, что порядок не определен (ключи с одинаковым значением будут в произвольном порядке в выходном списке).

ответ дан jimifiki 18 нояб. '10 в 17:19
источник
19
голосов

Это код:

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}
ответ дан PedroMorgan 08 марта '11 в 5:06
источник
18
голосов

Если значения являются числовыми, вы также можете использовать счетчик из коллекций

from collections import Counter

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


>> [('python', 5), ('world', 3), ('hello', 1)]    
ответ дан Ivan Sas 27 июня '12 в 18:43
источник
17
голосов

Вы можете использовать collections.Counter. Обратите внимание, что это будет работать как для числовых, так и для нечисловых значений.

>>> 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)])
ответ дан Abhijit 09 марта '13 в 15:30
источник
16
голосов

Вы можете создать "инвертированный индекс", также

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]
ответ дан S.Lott 05 марта '09 в 4:52
источник
13
голосов

Технически словари не являются последовательностями и поэтому не могут быть отсортированы. Вы можете сделать что-то вроде

sorted(a_dictionary.values())

Предполагая, что производительность не является огромной сделкой.

ответ дан Hank Gay 05 марта '09 в 3:56
источник
12
голосов

Почему бы не попробовать этот подход. Определим словарь под названием mydict со следующими данными:

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
ответ дан Nathaniel Payne 07 апр. '14 в 7:46
источник
10
голосов

Вы можете использовать skip 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(), тогда вы будете перебирать отсортированный порядок по значению.

Он реализован с использованием списка пропусков в datastructure.

ответ дан malthe 26 сент. '14 в 1:56
источник
10
голосов
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
ответ дан Argun 01 нояб. '10 в 15:16
источник
9
голосов

Это возвращает список пар ключ-значение в словаре, отсортированный по значению от наивысшего до самого низкого:

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

Для словаря, отсортированного по ключу, используйте следующее:

sorted(d.items(), reverse=True)

Возврат - это список кортежей, потому что сами словари не могут быть отсортированы.

Это может быть как напечатано, так и отправлено в дальнейшие вычисления.

ответ дан Zags 12 февр. '14 в 23:10
источник
6
голосов

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

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)

Еще один способ сделать это - использовать функцию labmda

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda t: t[1])
ответ дан Vishwanath Rawat 25 мая '17 в 21:13
источник
6
голосов

Используйте 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)]
ответ дан ponty 19 окт. '11 в 9:25
источник
5
голосов

Это работает в 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)
ответ дан iFail 16 нояб. '11 в 10:32
источник
5
голосов

Итерации через dict и сортировка по его значениям в порядке убывания:

$ 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
ответ дан juhoh 30 окт. '11 в 22:42
источник
5
голосов

Если ваши значения являются целыми числами, а вы используете Python 2.7 или новее, вы можете использовать collections.Counter вместо dict. Метод most_common предоставит вам все элементы, отсортированные по значению.

ответ дан Petr Viktorin 24 янв. '12 в 22:28
источник
4
голосов

Я придумал этот,

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

Для Python 3.x: x.items() вместо iteritems().

>>> sorted_x
{0: 0, 1: 2, 2: 1, 3: 4, 4: 3}

Или попробуйте с помощью collections.OrderedDict!

x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
from collections import OrderedDict

od1 = OrderedDict(sorted(x.items(), key=lambda t: t[1]))
ответ дан octoback 08 мая '13 в 11:17
источник
4
голосов

Вот решение, использующее zip на d.values() и d.keys(). Несколько строк вниз по этой ссылке (на объектах словаря):

Это позволяет создавать пары (значение, ключ), используя zip(): pairs = 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')]
ответ дан Scott 20 июня '15 в 4:44
источник
4
голосов

Вы можете использовать отсортированную функцию Python

sorted(iterable[, cmp[, key[, reverse]]])

Таким образом, вы можете использовать:

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

Перейдите по этой ссылке для получения дополнительной информации о отсортированной функции: https://docs.python.org/2/library/functions.html#sorted

ответ дан kkk 21 нояб. '14 в 18:04
источник
3
голосов

Для полноты, я отправляю решение, используя 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)]
ответ дан Abhijit 23 марта '13 в 17:19
источник
  • 1
  • 2

Другие вопросы по меткам