Как отсортировать словари по ключам в Python

Может ли кто-нибудь сказать мне, как я могу сортировать это:

{'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}

в

{'a': [1, 2, 3], 'b': ['blah', 'bhasdf', 'asdf'], 'c': ['one', 'two'],'d': ['asdf', 'wer', 'asdf', 'zxcv']}

? Спасибо!

UPDATE 1, пример кода:

Итак, я занимаюсь лингвистикой. Одна статья разбита на слова, которые хранятся в базе данных и имеют все виды свойств, включая идентификатор пара и идентификатор предложения. Задача: попытка восстановить исходный текст.

Получите 500 последовательных слов из DB

words = Words.objects.all()[wordId:wordId+500]
# I first create paragraphs, through which I can loop later in my django template,
# and in each para will be a list of words (also dictionaries). 
# So i am trying to get a dictionary with values that are lists of dictionaries. 
# 'pp' i make just for shorthanding a long-named variable.
paras={}
para_high = para_low =  words[0].belongs_to_paragraph
for w in words:
    last_word = w
    pp = w.belongs_to_paragraph
    if pp >para_high:
        para_high = pp
    if pp < para_low:
        para_low = pp
    if pp in paras:
        paras[pp].append(w)
    else:
        list = [w]
        paras[pp] = list
# Since there are blank lines between paragraphs, in rebuilding the text as it 
    #  looked originally, I need to insert blank lines. 
    # Since i have the ID of the paragraphs and they go somewhat like that: 1,3,4,8,9 
    #(the gaps between 1 & 3 and 4 & 8 i have to fill in with something else, 
    # which is why i had para_low and para_high to loop the range. 
isbr = True
for i in range(para_low, para_high+1):
    if i in paras:
        isbr = True
    else:
        if isbr:
            paras[i]=['break']
            isbr = False
        else:
            paras[i]=[]

В этот момент, однако, если я попытаюсь зациклить dict и перестроить текст, некоторые более поздние абзацы id'd появятся перед предыдущими, и это просто не делает этого.

UPDATE 2, код цикла:

        {% for k,v in wording.iteritems()  %}
        {% if v[0] == 'break' %}
        <br/>
        {% else %}
        </div><div class="p">{% for word in v %}{% if word.special==0%} {% endif %}<span class="word {% if word.special == 0%}clickable{% endif%}" wid="{{word.id}}" special="{{word.special}}" somethingElse={{word.somethingElse}}>{{ word.word }}</span>{% endfor %}
        {% endif %}
    {% endfor %}

Ответ 1

У Диктов нет порядка.

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

>>> sorted(d)
['a', 'b', 'c', 'd']

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

>>> sorted(d.items())
[
 ('a', [1, 2, 3]),
 ('b', ['blah', 'bhasdf', 'asdf']),
 ('c', ['one', 'two']),
 ('d', ['asdf', 'wer', 'asdf', 'zxcv'])
]

Если вы используете Python 2.7 или новее, вы также можете использовать OrderedDict.

подклассом

dict, который запоминает записи заказа, добавленные

Например:

>>> d = collections.OrderedDict(sorted(d.items()))
>>> for k, v in d.items():
>>>     print k, v
a [1, 2, 3]
b ['blah', 'bhasdf', 'asdf']
c ['one', 'two']
d ['asdf', 'wer', 'asdf', 'zxcv']

Ответ 2

Ответ правильный заключается в том, что если вы хотите, чтобы элементы словаря в отсортированном порядке, вы должны использовать функцию sorted() при прокрутке словаря:

for k, v in sorted(d.items()):
    print k, ':', v

или

for k in sorted(d):
   print d[k]

Или аналогичный.

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

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

Обновление: дальнейшее объяснение

Почему OrderedDict не является решением? Потому что OrderedDict упорядочен, не отсортирован.

Рассмотрим стандартный словарь:

>>> d = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}

Он не отсортирован, как мы видим ниже, "c" появится до "b". Он также не имеет порядка, если мы добавляем новые вещи, кажется, что кажется случайным порядком:

>>> d['g'] = 6
>>> d['i'] = 8
>>> d
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8}

ОК, поэтому используйте OrderedDict, затем:

>>> o = OrderedDict(sorted({'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}.items()))
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5)])

Ага! Сортировка! Так что OrderedDict работает!? Нет.

>>> o['i'] = 8
>>> o['g'] = 6
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('i', 8), ('g', 6)])

Что? Г закончилось после того, как я? Зачем!? Поскольку OrderedDict не сортируется, он упорядочивается. Он помнит порядок, который вы добавляете. Не сортировка. Это означает, что каждый раз, когда вы его используете, вам нужно сначала отсортировать его. OrderedDict будет сортироваться только до тех пор, пока вы не добавите к нему ключи. Но если вы не собираетесь его модифицировать, вам не нужен дикт. У вас также может быть список. Это то, что вы получаете из отсортированного():

>>> sorted(o.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

Но это работает также со стандартным словарем, поэтому OrderedDictionary не помогло:

>>> sorted(d.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

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

>>> for k in sorted(o):
...   print k, o[k]
... 
a 0
b 1
c 2
d 3
e 4
f 5
g 6
i 8

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

Ответ 3

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

Например:

>>> from sortedcontainers import SortedDict
>>> d = {'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}
>>> s = SortedDict(**d)
>>> s.keys()
SortedSet(['a', 'b', 'c', 'd'])

Вы также можете полностью заменить использование dict с помощью SortedDict, поскольку он поддерживает быстрые операции get/set и сортировку итераций элементов по ключевым словам.

Ответ 4

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

Если вы используете Python 2.7 или 3.1 или более позднюю версию, попробуйте collections.OrderedDict (2.7 docs; 3.1 docs, также см. PEP 372). Там есть ссылка в документах на версию pure-Python OrderedDict, которая работает с более ранними версиями Python.

Ответ 5

Также можно упомянуть самую маленькую рутину в heapq. Это сортирует и возвращает верхние N элементов. В зависимости от того, что на самом деле требуется, это может быть удобно, если вы играете с ключевым параметром. Я в основном упоминаю об этом, так как я обнаружил это пару ночей назад, и я сделал то, что было после. См. PEP 0265 и Heapq.

Ответ 6

Я добавлю один цент к тому, что уже объяснили другие. У меня была одна и та же проблема в одном конкретном случае. Мне нужно, чтобы выход моего словаря всегда был одинаковым для написания стабильных модульных тестов.

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

>>> d = {'a':1, 'b':2, 'c':3}
>>> print d
{'a': 1, 'c': 3, 'b': 2}

>>> from pprint import pprint
>>> pprint(d)
{'a': 1, 'b': 2, 'c': 3}

Ответ 7

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

Поместите этот код в отдельный файл с именем sdict.py:

def sortdict(dct):
    kys = dct.keys()
    kys.sort()
    from collections import OrderedDict
    d = OrderedDict()
    for x in kys: 
        for k, v in dct.iteritems():
            if (k == x):
                d[k] = v
    return d

Теперь поместите этот код в отдельный файл с именем test.py, чтобы протестировать его с помощью примерного словаря:

from sdict import sortdict
import json
dct = {'sizes':[32,28,42], 'dog':'schnauser', 'cat':'siamese', 'bird':'falcon'}
dctx = sortdict(dct)
print json.dumps(dctx) 

И, наконец, вызовите test.py из командной строки:

$ python test.py
{"bird": "falcon", "cat": "siamese", "dog": "schnauser", "sizes": [32, 28, 42]}

Я использую только строку json.dumps, чтобы показать вам, что это настоящий словарь, а не просто строковое представление. Вы также можете проверить его с помощью функции type().

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

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

По общему признанию, это работает только в python 2.7 или новее.

Приветствия,
- = Кэмерон