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

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

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

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

Ответы

Ответ 1

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

Например,

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)

Ответ 2

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

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

Ответ 3

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

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

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

Чтобы отсортировать его в порядке убывания, просто добавьте reverse=True:

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

Ответ 4

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

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

sorted(d.values())

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

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

Ответ 5

В последнем 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)])

Ответ 6

ОБНОВЛЕНИЕ: 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)])

Ответ 7

Почти так же, как ответ Хэнка Гея:

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

Или слегка оптимизирован, как это было предложено Джоном Фухи:

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

Ответ 8

Часто бывает очень удобно использовать 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

Ответ 9

По 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, как напомнил Раймонд Хеттингер во время обсуждения.

Ответ 10

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

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

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

Ответ 11

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

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

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

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

Ответ 12

В 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

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

Ответ 13

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

sorted(a_dictionary.values())

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

Ответ 14

Это код:

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}

Ответ 15

Если значения являются числовыми, вы также можете использовать 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)]    

Ответ 16

Попробуйте следующий подход. Определим словарь под названием 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

Ответ 17

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

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]

Ответ 18

Вы можете использовать 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)])

Ответ 19

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

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

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

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

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

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

Ответ 20

Начиная с 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.

Ответ 21

Вы можете использовать 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.

Ответ 22

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

Ответ 23

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

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)

Ответ 24

Как отмечает Dilettant, Python 3.6 теперь будет поддерживать порядок! Я думал, что у меня будет функция, которую я написал, которая облегчает сортировку итерируемого (кортеж, список, dict). В последнем случае вы можете сортировать либо по ключам, либо по значениям, и это может учитывать числовое сравнение. Только для> = 3.6!

Когда вы пытаетесь использовать сортировку для итерируемого, который содержит, например, строки и целые числа, sorted() завершится ошибкой. Конечно, вы можете форсировать сравнение строк с помощью str(). Однако в некоторых случаях вы хотите выполнить фактическое числовое сравнение, где 12 меньше 20 (что не так при сравнении строк). Итак, я придумал следующее. Когда вы хотите явное числовое сравнение, вы можете использовать флаг num_as_num который попытается выполнить явную числовую сортировку, пытаясь преобразовать все значения в числа с плавающей точкой. Если это удастся, он выполнит числовую сортировку, иначе он прибегнет к сравнению строк.

Комментарии по улучшению или push-запросы приветствуются.

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

Ответ 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')]

Ответ 26

Используйте 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)]

Ответ 27

Итерации через 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

Ответ 28

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

Ответ 29

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

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

Ответ 30

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

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

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

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

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