Як можна сортувати словник за ключем?


938

Що б хороший спосіб , щоб перейти від {2:3, 1:89, 4:5, 3:0}до {1:89, 2:3, 3:0, 4:5}?
Я перевірив деякі пости, але всі вони використовують "відсортований" оператор, який повертає кортежі.


39
Словники суттєво несортовані. Відображення словника - інша справа. У будь-якому випадку, для чого вам справді потрібно сортувати це?
Карл Кнечтел

15
словники не сортуються. вони просто не. якщо ви хочете пройти елементи для того, щоб вам довелося зробити щось подібне до вас, використовуючи сортування, наприклад "для ключа в сортованому (d.keys ())" припущенні, що d - назва вашого словника
Ryan Haining

3
@KarlKnechtel - мій приклад використання полягає в тому, що у мене є програма CLI, яка має примітивне меню, а параметри меню містяться у словнику як клавіші. Я хотів би відобразити клавіші в алфавітному порядку для зручності користувача.
Ренді


4
Зауважте, що дикти тепер упорядковуються порядком вставки (python 3.6+). Деякі відповіді нижче вказують на це.
matiasg

Відповіді:


939

Стандартні словники 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

Пітон 3

Для користувачів Python 3 потрібно використовувати .items()замість .iteritems():

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

1
Я використав це, і він працює, я думаю, його більше коду та надмірності, але виконує роботу, # не упорядкований dict d = {2: 3, 1:89, 4: 5, 3: 0} orderDict = {} для ключа в сортованому (d.iterkeys ()): orderDict [key] = d [key]
Антоній

4
@achrysochoou: якщо це спрацювало, то, мабуть, це було пощастило. Як вам сказали, звичайні словники не мають поняття сортування, незалежно від того, присвоюєте ви клавіші відсортовані чи випадковим чином.
Рікардо Карден

21
Для python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618

10
python 3.7+ не повинен бути замовленийDict, оскільки він тепер замовляє за замовчуванням :-)
Aneuway

3
З посібника python 3.7.4: "Виконання списку (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

(Пітон нижче 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
Ви також можете використовувати OrdersDict у python 2.4+, як у відповіді NPE
radtek

1
а якщо ви використовуєте елементи (), ви можете робити це як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=TrueOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
знизитись

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}

3
Іншим способом написання того ж самого є використання розуміння: {key:d[key] for key in sorted(d.keys())}
flow2k

41

Існує ряд модулів Python, які забезпечують реалізацію словника, які автоматично підтримують ключі у відсортованому порядку. Розглянемо модуль сортованих контейнерів, який є чистою реалізацією Python та швидкою реалізацією на C. Існує також порівняння продуктивності з іншими популярними варіантами, орієнтованими один на одного.

Використання впорядкованого диктату є неадекватним рішенням, якщо вам потрібно постійно додавати та видаляти пари ключів / значень, одночасно повторюючи.

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

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

6
sdце список кортежів, а не словник. (все ще корисно, хоча.)
nischi

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на консолі пітона або на них.


19

Знайшли інший спосіб:

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

upd:
1. це також сортує вкладені об'єкти (спасибі @DanielF).
2. Словники python не упорядковані, тому це підходить для друку або призначення лише для str.


Але це також сортує ключі вкладених об'єктів, які, можливо, не потрібні.
Даніель Ф

Зауважте, що це лише сортування словників, а не списки, наприклад dict.keys () не буде відсортовано, оскільки це список.
Андрій


13

Словник Python був не упорядкований перед Python 3.6. У CPython реалізації Python 3.6 словник зберігає порядок вставки. З Python 3.7 це стане мовною особливістю.

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

Аспект збереження порядку в цій новій реалізації вважається детальною інформацією про реалізацію, і на неї не слід покладатися (це може змінитися в майбутньому, але бажано мати нову реалізацію диктату мовою протягом декількох випусків, перш ніж змінювати специфікацію мови призначати збереження порядку для семантики для всіх поточних та майбутніх реалізацій Python; це також допомагає зберегти зворотну сумісність із старими версіями мови, де досі діє порядок випадкової ітерації, наприклад, Python 3.5).

У документі Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dic Dictionary ):

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

Отже, на відміну від попередніх версій, ви можете сортувати дикт після Python 3.6 / 3.7. Якщо ви хочете сортувати вкладений дікт, включаючи підрозділ всередині, ви можете зробити:

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 за допомогою ключа 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)]

Отже, змінивши їх у ключі, значення та предмети, ви можете надрукувати як те, що вам потрібно. Сподівайтеся, це допомагає!


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

Що означає "виразна поведінка з різними словниками"? Що таке "чітка поведінка", з якою сортування не може впоратися?
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

6

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

Це ваш словник

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

Створіть новий словник d1, сортуючи це d за допомогою функції лямбда

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 для їх відображення, але ОП справді запитав про "перехід" від несортованого до відсортованого зображення, тобто ОП, схоже, хоче щось, що залишається відсортованим у пам'яті, можливо, для якогось алгоритму, який вимагає відсортованих ключів
Капітан Лептон

Цей метод не дозволить присвоїти ланцюжок, оскільки 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

Найпростішим рішенням є те, що ви повинні отримати список ключів диктату, відсортований порядок, а потім повторити переказ. Наприклад

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} 

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 

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з нуля, коли ви йдете разом. Майте другу структуру даних, список зі своїм списком ключів. Пакет бісект має функцію insort, яка дозволяє вставляти в відсортований список або сортувати список після повного заповнення вашого dict. Тепер, коли ви перебираєте свій дікт, ви замість цього перебираєте список, щоб отримати доступ до кожного ключа в порядку, не турбуючись про представлення структури дикту (яка не була зроблена для сортування).


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

3
Є ще 14 відповідей. Чи можете ви пояснити свій код трохи і чому він може бути кращим за інші рішення?
FelixSFD

Укорочений - Досить нечитабельний код з короткими безглуздими назвами змінних l, l2, l3. Здається, це спроба непрямого та неефективного алгоритму, що не знає стандартних функцій python, і ні в якому разі не працює при тестуванні на невеликому прикладі в оригінальному пості.
Капітан Лептон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.