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

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

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

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

2776
задан Gern Blanston 05 марта '09 в 3:49
источник поделиться
39 ответов
  • 1
  • 2

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

Например,

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

Проще, чем: 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]

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

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

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

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

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

573
ответ дан Mark 13 февр. '10 в 19:33
источник поделиться

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

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

sorted(d.values())

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

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

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

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

Часто бывает очень удобно использовать 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
59
ответ дан Remi 30 авг. '11 в 3:30
источник поделиться

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


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

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


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

51
ответ дан user26294 05 марта '09 в 4:06
источник поделиться

По 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 мы теперь сможем использовать встроенную -in dict для поддержания порядка вставки!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

41
ответ дан Dilettant 10 сент. '16 в 13:05
источник поделиться

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

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 исходным словарем.

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

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

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

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

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

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

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

В 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

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

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

Это код:

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

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

from collections import Counter

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


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

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

sorted(a_dictionary.values())

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

17
ответ дан Hank Gay 05 марта '09 в 3:56
источник поделиться

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

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

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

Почему бы не попробовать этот подход. Определим словарь под названием 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
12
ответ дан Nathaniel Payne 07 апр. '14 в 7:46
источник поделиться

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

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

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

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

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

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

12
ответ дан Zags 12 февр. '14 в 23: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.

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

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

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])
10
ответ дан Vishwanath Rawat 25 мая '17 в 21:13
источник поделиться

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

Вот решение, использующее 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')]
6
ответ дан Scott 20 июня '15 в 4:44
источник поделиться

Итерации через 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
5
ответ дан juhoh 30 окт. '11 в 22:42
источник поделиться

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

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

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

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]))
5
ответ дан octoback 08 мая '13 в 11:17
источник поделиться

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

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

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

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

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

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

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

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

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

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

Если у вас нет Python 2.7 или выше, лучшее, что вы можете сделать, это перебрать значения в функции генератора. (Здесь есть OrderedDict для 2.4 и 2.6 здесь, но

a) I don't know about how well it works 

и

b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option out.)

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 или выше

4
ответ дан ytpillai 31 июля '15 в 11:08
источник поделиться
  • 1
  • 2

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