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

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

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

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

30 ответов


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

например,

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

просто: sorted(dict1, key=dict1.get)

ну, на самом деле можно сделать "сортировку по словарным значениям". Недавно мне пришлось сделать это в коде Golf (Stack Overflow question код гольф: диаграмма частоты слов). В сокращенном виде проблема была такой: учитывая текст, подсчитайте, как часто встречается каждое слово и отобразите список верхних слов, отсортированных по убывающей частоте.

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

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]

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


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

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

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


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

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

sorted(d.values())

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

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

в недавнем 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)])

обновление: 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)])

это часто может быть очень удобно использовать namedtuple. Например, у вас есть словарь "name" в качестве ключей и "score" в качестве значений, и вы хотите сортировать по "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)

теперь вы можете получить имя и счет, скажем, второго лучшего игрока (индекс=1) Очень Питонически, как это:

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

почти то же самое, что и ответ Хэнка Гея;


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

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


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


по состоянию на Python 3.6 встроенный дикт будет заказан

хорошие новости, поэтому исходный вариант использования 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 году компанией Raymond Hettinger (ср. почта на python-dev с тема "более компактные словари с более быстрой итерации") и сейчас (в 2016 году) заявил в адрес Виктора Stinner в python-dev с темой "Python 3.6 dict становится компактным и получает закрытую версию; и ключевые слова становятся упорядоченными" из-за исправления/реализации проблемы 27350 "компактный и заказал словарь" в Python 3.6 теперь мы сможем использовать встроенный дикт для поддержания порядка вставки!!

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

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

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

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

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

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

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

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

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

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

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

на Почта в список python-dev, Гвидо ван Россум заявил:

сделать так. "Dict сохраняет порядок вставки" - это постановление. Спасибо!

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


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

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

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

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


У меня была такая же проблема, и я решал его так:

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

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

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


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

копипаст из : http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

наслаждаться ;-)


этот код:

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}

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

from collections import Counter

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


>> [('python', 5), ('world', 3), ('hello', 1)]    

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

sorted(a_dictionary.values())

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


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

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]

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

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

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

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

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


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

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

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

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

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

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


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

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

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

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

Это позволяет создать (значение, ключ) пар с помощью zip(): пар = молния(д. значения(), д. ключи()).

Итак, мы можем сделать следующее:

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

использовать ValueSortedDict С словарь:

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

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

$ 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

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

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

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

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

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

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

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


конечно, помните, что вам нужно использовать 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's 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 или выше


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

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

комментарии для улучшения или 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")

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