Как я могу отсортировать словарь по ключу?

941

Что бы хороший способ , чтобы перейти от {2:3, 1:89, 4:5, 3:0}к {1:89, 2:3, 3:0, 4:5}?
Я проверил некоторые сообщения, но все они используют оператор «сортировка», который возвращает кортежи.

Antony
источник
39
Словари изначально не отсортированы. Отображение словаря - другое дело. В любом случае, зачем вам это нужно сортировать?
Карл Кнехтель
15
словари не отсортированы. они просто не если вы хотите просмотреть элементы в порядке, то вам нужно будет сделать что-то, как вы сказали, используя sorted, например «for key in sorted (d.keys ())», предполагая, что d - это имя вашего словаря
Ryan Haining
3
@KarlKnechtel - мой пример использования - у меня есть приложение CLI, у которого есть примитивное меню, а пункты меню находятся в словаре в качестве ключей. Я хотел бы отобразить ключи в алфавитном порядке для здравомыслия пользователя.
Рэнди
4
Обратите внимание, что дикты теперь упорядочены по порядку вставки (python 3.6+). Некоторые ответы ниже указывают на это.
matiasg

Ответы:

941

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

Самый простой способ - использовать OrderedDict, который запоминает порядок, в котором были вставлены элементы:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

Не берите в голову способ od, которым распечатан; это будет работать как ожидалось:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

Для пользователей Python 3 необходимо использовать .items()вместо .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
источник
1
Я использовал это, и это работает, я думаю, это больше кода и избыточности, но выполняет свою работу, # неупорядоченный dict d = {2: 3, 1:89, 4: 5, 3: 0} orderDict = {} для ключа в отсортированном виде (d.iterkeys ()): orderDict [ключ] = d [ключ]
Антоний
4
@achrysochoou: если это сработало, это, должно быть, просто удача. Как вам сказали, обычные словари не имеют понятия сортировки, независимо от того, назначаете ли вы отсортированные ключи или случайным образом.
Рикардо Карденес
21
Для python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618
10
python 3.7+ не должен нуждаться в orderDict, поскольку теперь он заказывает по умолчанию :-)
Aneuway
3
Из руководства по python 3.7.4: «Выполнение list (d) в словаре возвращает список всех ключей, используемых в словаре, в порядке вставки». Таким образом, порядок вставки - это то, что сохраняется, и на него можно положиться.
Мостафа Хадиан,
415

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

В Python 2.4 и выше:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

for key in sorted(mydict):
    print "%s: %s" % (key, mydict[key])

дает:

alan: 2
bob: 1
carl: 40
danny: 3

(Python ниже 2.4 :)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Источник: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/

Джеймс
источник
2
Вы также можете использовать OrderedDict в Python 2.4+, как в ответе NPE
radtek
1
и если вы используете items (), вы можете сделать это какfor key, value in sorted(mydict.items())"
beep_check
Сами словари не имеют заказанных предметов как таковых -> больше не соответствуют действительности!
Minexew
Как же ты можешь объяснить?
Джеймс
204

Из документации библиотеки Pythoncollections :

>>> from collections import OrderedDict

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> 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)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
Деннис
источник
4
классно! Ребята, если вы хотите изменить порядок (по возрастанию или по убыванию), вы просто добавляете, reverse=Trueнапример,OrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia
1
В PyCharm, независимо от того, какой словарь я использую, я всегда получаю это предупреждение:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

Для CPython / PyPy 3.6 и любого Python 3.7 или выше это легко сделать с помощью:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
источник
3
Другой способ написать то же самое - использовать понимание: {key:d[key] for key in sorted(d.keys())}
flow2k
42

Существует ряд модулей Python, которые предоставляют реализации словаря, которые автоматически поддерживают ключи в отсортированном порядке. Рассмотрим модуль sortedcontainers, представляющий собой реализации на чистом Python и fast-as-C. Существует также сравнение производительности с другими популярными опциями, сравниваемыми друг с другом.

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

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

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

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])
GrantJ
источник
32

Просто:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Вывод:

1 89
2 3
3 0
4 5
user3769249
источник
6
sdэто список кортежей, а не словарь. (все еще полезно.)
нищи
24

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

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Обратите внимание, что это ничего не меняет в том, как хранятся ключи, в каком порядке они будут возвращаться, когда вы перебираете их и т. Д., А также в том, как они отображаются printна консоли Python или на консоли.

Брайан
источник
19

Нашел другой способ:

import json
print json.dumps(d, sort_keys = True)

upd:
1. это также сортирует вложенные объекты (спасибо @DanielF).
2. Словари python неупорядочены, поэтому это подходит для печати или присваивания только str.

tschesseket
источник
Но это также сортирует ключи вложенных объектов, которые могут быть не нужны.
Даниэль Ф
Обратите внимание, что это только сортирует словари, а не списки, например, dict.keys () не будет отсортирован, потому что это список.
Андрей
16

В Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

дает

1 89
2 3
3 0
4 5
Евгений Трястин
источник
13

Словарь Python был неупорядочен до Python 3.6. В реализации Python 3.6 для CPython словарь сохраняет порядок вставки. Начиная с Python 3.7, это станет функцией языка.

В журнале изменений Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

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

В документе Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

Выполнение list (d) в словаре возвращает список всех ключей, используемых в словаре, в порядке вставки (если вы хотите, чтобы он был отсортирован, просто используйте вместо него sorted (d)).

Таким образом, в отличие от предыдущих версий, вы можете сортировать слова после Python 3.6 / 3.7. Если вы хотите отсортировать вложенный dict, включающий в себя sub-dict внутри, вы можете сделать:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: sort_dict(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb

Гуанъян Ли
источник
11

Здесь я нашел простейшее решение для сортировки python dict по ключу pprint. например.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

но при использовании pprint он вернет отсортированный dict

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}
Атул Арвинд
источник
10

Существует простой способ сортировки словаря.

По вашему вопросу

Решение:

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Где c, это название вашего словаря.)

Эта программа дает следующий вывод:

[(1, 89), (2, 3), (3, 0), (4, 5)]

как ты и хотел.

Другой пример:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Дает вывод:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Дает вывод:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Дает вывод:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

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

Sree
источник
8

Будет генерировать именно то, что вы хотите:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

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

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
JAX
источник
Что означает «показывать отличное поведение в разных словарях»? Что такое «отличное поведение», которое не может быть рассортировано?
ingyhere
6

Я думаю, что самое простое - отсортировать данные по ключу и сохранить отсортированную пару ключ: значение в новом файле.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

Чтобы было понятнее:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value
lallolu
источник
6

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

Это твой словарь

d = {2:3, 1:89, 4:5, 3:0}

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

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 должно быть {1: 89, 2: 3, 3: 0, 4: 5}, отсортировано по ключам в d.

Амит Прафулла
источник
5

Диктофоны Python не упорядочены. Обычно это не проблема, так как наиболее распространенный вариант использования - поиск.

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

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

Если вам нужно выполнить итерацию, как предлагали другие, самый простой способ - выполнить итерацию по отсортированным ключам. Примеры-

Вывести значения, отсортированные по ключам:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Получить список значений, отсортированных по ключам:

values = [d[k] for k in sorted(d.keys())]
Рамашиш Баранвал
источник
2
for k,value in sorted(d.items()):лучше: избегает доступа к диктовке по ключу снова в цикле
Жан-Франсуа Фабр
4

Я придумываю однострочную сортировку.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

Надеюсь, это будет полезно.

Дживан Чайтанья
источник
4

Эта функция будет рекурсивно сортировать любой словарь по его ключу. То есть, если какое-либо значение в словаре также является словарем, оно также будет отсортировано по его ключу. Если вы работаете на CPython 3.6 или выше, можно сделать простое изменение, dictа не использовать OrderedDict.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)
Бубу
источник
2

Ребята, вы все усложняете ... это действительно просто

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

Выход:

{'A':2,'B':1,'C':3}
Дерик Фдо
источник
Проголосовал, потому что я не знал словарей сортировки pprint для их отображения, но OP действительно спросил о «переходе» от несортированного к отсортированному dict, т.е. OP, кажется, хочет что-то, что остается отсортированным в памяти, возможно, для некоторого алгоритма, который требует отсортированные ключи
Капитан Лептон
Этот метод не разрешает связанное присваивание, так как pprint не возвращает ничего. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (последний вызов был последним): файл "<stdin>", строка 1, в <module> AttributeError: у объекта 'NoneType' нет атрибута 'type'
2

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

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

Ниже будет вывод (в порядке убывания)

e 30
b 13
d 4
c 2
a 1
Шафик
источник
2

Простой способ сделать это:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 
pr94
источник
1

Сравнение времени двух методов в 2.7 показывает, что они практически идентичны:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 
Jesuisme
источник
1
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)
Мохаммад Маджуб
источник
1
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}
Махди Геличи
источник
0

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

Построить dictс нуля, как вы идете вместе. Есть вторая структура данных, список, с вашим списком ключей. В пакете bisect есть функция insort, которая позволяет вставлять в отсортированный список или сортировать ваш список после полного заполнения вашего dict. Теперь, когда вы перебираете свой dict, вы вместо этого перебираете список, чтобы обращаться к каждому ключу по порядку, не беспокоясь о представлении структуры dict (которая не была создана для сортировки).

demongolem
источник
0

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

Тем не менее, учитывая то, как все должно быть сделано на самом деле, принимая во внимание десятилетия и десятилетия компьютерных наук, я пришел к моему полному удивлению, что на самом деле здесь есть только один ответ (от пользователя GrantJ ), предполагающий использование отсортированных ассоциативных контейнеров (sortedcontainers), которые сортирует элементы по ключу в точке их вставки.

Это позволит избежать значительного влияния на производительность для каждого вызова sort(...)(как минимум O(N*log(N)), где Nесть количество элементов (логически, это относится ко всем таким решениям, которые предлагают использовать sort(...)). Примите во внимание, что для всех таких решений sort(...)потребуется вызываться каждый раз, когда необходимо получить доступ к коллекции как отсортированный ПОСЛЕ того, как она была изменена путем добавления / удаления элементов ...

Петерб
источник
-1
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)
user7070507
источник
3
Есть 14 других ответов. Можете ли вы объяснить свой код немного, и почему он может быть лучше, чем другие решения?
FelixSFD
Downvoted - довольно нечитаемый код с короткими бессмысленными именами переменных l, l2, l3. Кажется, что это попытка косвенного и неэффективного алгоритма без знания стандартных функций Python, и в любом случае не работает при тестировании на небольшом примере в оригинальном посте.
Капитан Лептон