2012-06-18 6 views
21

Я работаю над python 3.2.2. Ломать голову более 3 часов, чтобы отсортировать словарь по его клавишам. Мне удалось сделать его отсортированным списком с 2 аргументами, но в конце он не может сделать его отсортированным.сортировочный словарь python 3

Это то, что я никогда понял:

myDic={10: 'b', 3:'a', 5:'c'} 
sorted_list=sorted(myDic.items(), key=lambda x: x[0]) 

Но независимо от того, что я не могу сделать словарь из этого отсортированного списка. Как мне это сделать? Благодаря!

+3

Что вы подразумеваете под «не может сделать словарь из этого отсортированного списка»? По определению словарь не сортируется. Если вы хотите отсортированный словарь, посмотрите на [упорядоченные словари] (http://docs.python.org/release/3.1.5/whatsnew/3.1.html#pep-372-ordered-dictionaries). – inspectorG4dget

+0

+1, потому что я помню, что у меня была такая же проблема (некоторое время назад, когда OrderedDict даже официально был в коллекциях!), И я помню разочарование ... – jsh

ответ

31

dict не сохраняет порядок своих элементов. Что вам нужно, это OrderedDict: http://docs.python.org/library/collections.html#collections.OrderedDict

редактировать

Пример использования:

>>> from collections import OrderedDict 
>>> a = {'foo': 1, 'bar': 2} 
>>> a 
{'foo': 1, 'bar': 2} 
>>> b = OrderedDict(sorted(a.items())) 
>>> b 
OrderedDict([('bar', 2), ('foo', 1)]) 
>>> b['foo'] 
1 
>>> b['bar'] 
2 
+0

Я не могу сделать такой объект OrderedDict, я набираю OrderedDict = {}, но его просто регулярная переменная с именем OrderedDict .. – Jjang

+3

@Jjang, 'OrderedDict = {}' просто создает обычный словарь под названием «OrderedDict». Вам нужно сделать 'из коллекции import OrderedDict', а затем инициализировать что-то вроде' myOrdDic = OrderedDict() '. –

+0

@Jjang Я добавил пример использования для ясности. –

9

Python обыкновенных dicts не может быть сделано, чтобы обеспечить ключи/элементы в любом определенном порядке. Для этого вы можете использовать тип OrderedDict из модуля collections. Обратите внимание, что тип OrderedDict просто хранит запись порядка вставки. Вам нужно будет отсортировать записи до инициализации словаря, если вы хотите, чтобы последующие представления/итераторы возвращали элементы в порядке каждый раз. Например:

>>> myDic={10: 'b', 3:'a', 5:'c'} 
>>> sorted_list=sorted(myDic.items(), key=lambda x: x[0]) 
>>> myOrdDic = OrderedDict(sorted_list) 
>>> myOrdDic.items() 
[(3, 'a'), (5, 'c'), (10, 'b')] 
>>> myOrdDic[7] = 'd' 
>>> myOrdDic.items() 
[(3, 'a'), (5, 'c'), (10, 'b'), (7, 'd')] 

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

Edit: Так, если объект сортировки данных, просто напечатать его в порядке, в формате напоминающий питона dict объект, что-то вроде следующего должно хватить:

def pprint_dict(d): 
    strings = [] 
    for k in sorted(d.iterkeys()): 
     strings.append("%d: '%s'" % (k, d[k])) 
    return '{' + ', '.join(strings) + '}' 

Обратите внимание, что эта функция не является гибким w/r/t типов ключей, пар значений (т. е. он ожидает, что ключи будут целыми и соответствующие значения будут строками). Если вам нужна большая гибкость, вместо этого используйте что-то вроде strings.append("%s: %s" % (repr(k), repr(d[k]))).

+0

+1 для «другой структуры данных». «OrderedDict» больше похож на гибридный dict/queue; если вы не будете использовать «очередь» для решения своей проблемы, «OrderedDict», вероятно, также не является правильным решением. – senderle

+1

@ senderle, честно говоря, мне еще предстоит столкнуться с одной ситуацией в любой моей работе, в которой было бы целесообразно использовать «OrderedDict». Это не значит, что это не разумный класс, но я бы сказал, что он играет очень нишу. –

+0

, но в конце он остается списком, а не dict ... когда вы печатаете OrderedDict, он печатает как список, с(), а не {}, как dict ... И мне нужно печатать в формате dict в end – Jjang

0

Мне нравится python numpy для такого рода вещей! например:

r=readData() 
nsorted = np.lexsort((r.calls, r.slow_requests, r.very_slow_requests, r.stalled_requests)) 

У меня есть пример импорта CSV-данных в numpy и упорядочение по приоритетам столбцов. https://github.com/unixunion/toolbox/blob/master/python/csv-numpy.py

Kegan

+0

Звучит как китайский для меня, извините – Jjang

11

Я не думаю, что вы хотите OrderedDict. Похоже, вы предпочтете SortedDict, то есть dict, который поддерживает свои ключи в отсортированном порядке. Модуль sortedcontainers предоставляет именно такой тип данных. Он написан в версиях pure-Python, fast-as-C, имеет 100% -ый охват и часы стресса.

Установка проста с пипом:

pip install sortedcontainers 

Обратите внимание, что если вы не можете pip install, то вы можете просто вытащить исходные файлы из хранилища с открытым исходным кодом.

Тогда вы код просто:

from sortedcontainers import SortedDict 
myDic = SortedDict({10: 'b', 3:'a', 5:'c'}) 
sorted_list = list(myDic.keys()) 

Модуль sortedcontainers также поддерживает performance comparison с другими популярными реализациями.

+2

Для тех, кто использует Anaconda, теперь это доступно как установка conda с использованием 'conda install sortedcontainers' – TMWP

0

Может быть не так хорошо, но я полагал, что это:

def order_dic(dic): 
    ordered_dic={} 
    key_ls=sorted(dic.keys()) 
    for key in key_ls: 
     ordered_dic[key]=dic[key] 
    return ordered_dic 
+1

Вы действительно попробовали свой код? Я сомневаюсь, что это вообще работает. Ваш 'ordered_dic' так же несортирован, как' dic'. Когда вы повторяете стандартный 'dict', элементы не возвращаются в том порядке, в котором они были вставлены. Для этого вам нужен «OrderedDict». –

0

Любое современное решение этой проблемы? я работал вокруг него с:

order = sorted([ job['priority'] for job in self.joblist ]) 
    sorted_joblist = [] 
    while order: 
     min_priority = min(order) 
     for job in self.joblist: 
      if job['priority'] == min_priority: 
       sorted_joblist += [ job ] 
       order.remove(min_priority) 
    self.joblist = sorted_joblist 

список заданий отформатирован как: JobList = [{ 'приоритета': 3, 'Имя': 'Foo', ...}, { 'приоритет': 1 , «имя»: «бар», ...}]

  • в основном я создаю список (заказ) со всеми элементами, с помощью которого я хочу, чтобы отсортировать Dict
  • я перебирать этот список и dict, когда я нахожу элемент на dict, я отправляю его в новый dict и удаляю элемент из «order».

Кажется, что вы работаете, но я полагаю, что есть лучшие решения.

0

Современное и быстрое решение для Python 3.7. Может также работать в некоторых интерпретаторах Python 3.6.

TLDR

Чтобы отсортировать словарь по клавишам:

sorted_dict = {k: disordered[k] for k in sorted(disordered)} 

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

Комментарий от принятого ответа

Пример в принятом ответе не использует параметр key для sorted(), который (как должное, выглядит красиво и требует меньше печатать) происходит медленнее, поскольку оба элемента сгенерированных кортежей (key, value) являются в сравнении. Поскольку словари Python не могут иметь два элемента с одним и тем же ключом, использование второго элемента кортежа для сравнения не требуется.

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

Большие изменения в Python 3.7, что the dictionaries are now ordered by default.

  • Вы можете сгенерировать отсортированный dict с использованием определений dict.
  • Использование OrderedDict может быть предпочтительным для обеспечения совместимости.
  • Не используйте sorted(d.items()) без key.

См:

disordered = {10: 'b', 3: 'a', 5: 'c'} 

# sort keys, then get values from original - fast 
sorted_dict = {k: disordered[k] for k in sorted(disordered)} 

# key = itemgetter - slower 
from operator import itemgetter 
key = itemgetter(0) 
sorted_dict = {k: v for k, v in sorted(disordered.items(), key=key)} 

# use key = lambda - the slowest 
key = lambda item: item[0] 
sorted_dict = {k: v for k in sorted(disordered.items(), key=key)} 

Вообще

Timing Результаты:

Best for {k: d[k] for k in sorted(d)}: 7.507327548999456 
Best for {k: v for k, v in sorted(d.items(), key=key_getter)}: 12.031082626002899 
Best for {k: v for k, v in sorted(d.items(), key=key_lambda)}: 14.22885995300021 

Best for dict(sorted(d.items(), key=key_getter)): 11.209122000000207 
Best for dict(sorted(d.items(), key=key_lambda)): 13.289728325995384 
Best for dict(sorted(d.items())): 14.231471302999125 

Best for OrderedDict(sorted(d.items(), key=key_getter)): 16.609151654003654 
Best for OrderedDict(sorted(d.items(), key=key_lambda)): 18.52622927199991 
Best for OrderedDict(sorted(d.items())): 19.436101284998585 

тестирования кода:

from timeit import repeat 

setup_code = """ 
from operator import itemgetter 
from collections import OrderedDict 
import random 
random.seed(0) 
d = {i: chr(i) for i in [random.randint(0, 120) for repeat in range(120)]} 
key_getter = itemgetter(0) 
key_lambda = lambda item: item[0] 
""" 

cases = [ 
    # fast 
    '{k: d[k] for k in sorted(d)}', 
    '{k: v for k, v in sorted(d.items(), key=key_getter)}', 
    '{k: v for k, v in sorted(d.items(), key=key_lambda)}', 
    # slower 
    'dict(sorted(d.items(), key=key_getter))', 
    'dict(sorted(d.items(), key=key_lambda))', 
    'dict(sorted(d.items()))', 
    # the slowest 
    'OrderedDict(sorted(d.items(), key=key_getter))', 
    'OrderedDict(sorted(d.items(), key=key_lambda))', 
    'OrderedDict(sorted(d.items()))', 
] 

for code in cases: 
    times = repeat(code, setup=setup_code, repeat=3) 
    print(f"Best for {code}: {min(times)}") 
Смежные вопросы