Как отсортировать словари по ключам в Python - PullRequest
18 голосов
/ 10 января 2011

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

{'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']}

?Спасибо!

ОБНОВЛЕНИЕ 1, пример кода:

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

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

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's 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]=[]

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

ОБНОВЛЕНИЕ 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 %}

Ответы [ 7 ]

46 голосов
/ 10 января 2011

У Dicts нет заказа.

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

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

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

>>> 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']
29 голосов
/ 10 января 2011

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

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

или

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

или аналогичные.

Упомянутый OrderedDict предназначен для словарей, имеющих порядок.И порядок не такой, как сортировка.Да, вы можете создать отсортированный OrderedDict, но как только вы добавляете новый ключ, он больше не сортируется. Так что вам все равно придется использовать sorted () для сортировки перед каждым использованием или после каждой манипуляции.Таким образом, 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)])

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

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

5 голосов
/ 28 марта 2014

Стоит отметить, что в Python есть несколько реализаций словаря, которые поддерживают ключи в отсортированном порядке. Рассмотрим модуль sortedcontainers , который является реализациями на чистом 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 , поскольку оно поддерживает быстрые операции получения / установки и сортировку итераций элементов по ключу.

1 голос
/ 10 января 2011

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

Если вы используете Python 2.7 или 3.1 или более позднюю версию, попробуйте collections.OrderedDict ( 2,7 документа ; 3,1 документа ; также см. PEP 372 ).В документации есть ссылка на версию на языке Python OrderedDict , которая работает на более ранних версиях Python.

0 голосов
/ 14 сентября 2017

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

Поместите этот код в отдельный файл с именем 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 ().

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

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

Правда, это работает только в Python 2.7 или новее.

Ура,
- = Cameron

0 голосов
/ 10 января 2011

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

Если случайно это то, что вы пытаетесь достичь, или какая-то другая задача, связанная с выводом, вам вообще ничего не нужно сортировать, просто используйте модуль 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}
0 голосов
/ 10 января 2011

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

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