Вопрос по dictionary, sorting, python – Сортировать словарь словарей по нескольким значениям дочернего словаря

1

У меня есть словарь, который выглядит так:

myDict = {
    'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'},
    'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'},
    'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'},
    'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'},
    'ABC12346': {'serial_num': 'ABC12346', 'site_location': 'Europe'}
}

Моя цель - отсортировать этот словарь поsite_location иserial_num каждого из детских словарей.

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

Это мой код:

import pprint
items = ((k, k2, v) for k in myDict for k2, v in myDict[k].items())
ordered = sorted(items, key=lambda x:x[-1], reverse=False)
pprint.pprint(ordered)

Вот результат, который я получаю:

[('ABC12346', 'site_location', 'Europe'),
 ('SER12345', 'site_location', 'North America'),
 ('SER12346', 'site_location', 'North America'),
 ('SER12347', 'site_location', 'South America'),
 ('ABC12345', 'site_location', 'South America'),
 ('ABC12346', 'serial_num': 'ABC12346'),
 ('SER12345', 'serial_num': 'SER12345'),
 ('SER12346', 'serial_num': 'SER12346'),
 ('SER12347', 'serial_num': 'SER12347'),
 ('ABC12345', 'serial_num': 'ABC12345')]

Я ожидал чего-то большего, хотя это:

{
    'ABC12346': {'serial_num': 'ABC12346', 'site_location': 'Europe'}
    'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'},
    'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'},
    'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'},
    'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'},
}

Фактическим результатом является разделение серийного номера и местоположения сайта. Я хочу сохранить их вместе в отсортированном объекте. Как я могу это сделать?

Последний фрагмент не является допустимым Python - вы не можете иметь ключи в списках. georg
@ thg435, ты прав. Это было отсутствие удержания смены. Предполагается, что это будет словарь, но я был бы счастлив со всем, что было заказано таким образом. Список кортежей или подобных мне подходит. Andy♦
@ Andy, если вы хотите отсортировать структуру словаря, используйте OrderedDict, как показано ниже Maria Zverina

Ваш Ответ

4   ответа
1

не могут быть отсортированы. Если вы хотите внешний вид отсортированного словаря, вам нужно создать отсортированный список и затем вставить его в класс OrderedDict. Фрагмент кода ниже иллюстрирует это:

from collections import OrderedDict

myDict = {
    'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'},
    'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'},
    'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'},
    'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'},
    'ABC12346': {'serial_num': 'ABC12346', 'site_location': 'Europe'}
}

def sortfun(d):
    return (d[1]['site_location'], d[1]['serial_num'])

skv = sorted(myDict.iteritems(), key=sortfun)
sorted_dict = OrderedDict(skv)

print sorted_dict
вы можете просто вернуть кортеж изsortfun
@Claudiu Хороший вопрос - это выглядит намного чище - обновлено выше
1
>>> import pprint
>>> dic=myDict.items()
>>> dic.sort(key=lambda x:(x[1]['site_location'],x[1]['serial_num']))
>>> pprint.pprint([{k:v} for k,v in dic])
[{'ABC12346': {'serial_num': 'ABC12346', 'site_location': 'Europe'}},
 {'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'}},
 {'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'}},
 {'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'}},
 {'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'}}]
0

cmp (Я думаю, вы должны использовать это, так как мы используем комбинацию из 2 клавиш), но это не очень красиво, я думаю, это можно улучшить:

>>> pprint(sorted(myDict.items(), cmp=lambda x, y: cmp((x[1]['site_location'], x[1]['serial_num']), (y[1]['site_location'], y[1]['serial_num']))))
[('ABC12346', {'serial_num': 'ABC12346', 'site_location': 'Europe'}),
 ('SER12345', {'serial_num': 'SER12345', 'site_location': 'North America'}),
 ('SER12346', {'serial_num': 'SER12346', 'site_location': 'North America'}),
 ('ABC12345', {'serial_num': 'ABC12345', 'site_location': 'South America'}),
 ('SER12347', {'serial_num': 'SER12347', 'site_location': 'South America'})]
с помощьюkey намного чище все, что вы делаете, по сути делаcmp на двух значениях, которыеkey будет возвращаться, за исключением того, что значения не кэшируются (как они делают сkey). Это работает потому, что кортежи сравниваются так, как вы думаете, поэтомуkey возвращает кортеж, он сравнивает несколько значений.
4

dicts = [{k: v} for (k,v) in myDict.items()]
dicts.sort(key=lambda d: (d.values()[0]['site_location'], d.values()[0]['serial_num'],))

Выход для выполнения:

import pprint
pprint.pprint(dicts)

является:

[{'ABC12346': {'serial_num': 'ABC12346', 'site_location': 'Europe'}},
 {'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'}},
 {'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'}},
 {'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'}},
 {'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'}}]

РЕДАКТИРОВАТЬ: Я собирался ваш ответ для выходного формата, но это, вероятно, будет иметь больше смысла:

dicts = myDict.items()
dicts.sort(key=lambda (k,d): (d['site_location'], d['serial_num'],))

Выход:

[('ABC12346', {'serial_num': 'ABC12346', 'site_location': 'Europe'}),
 ('SER12345', {'serial_num': 'SER12345', 'site_location': 'North America'}),
 ('SER12346', {'serial_num': 'SER12346', 'site_location': 'North America'}),
 ('ABC12345', {'serial_num': 'ABC12345', 'site_location': 'South America'}),
 ('SER12347', {'serial_num': 'SER12347', 'site_location': 'South America'})]
На примере кортежа, как я могу отсортировать поsite_location вместо серийного номера? Andy♦
@ Энди: о, моя ошибка, отредактировал это. это должно было быть(d['site_location'], d['serial_num'])не(k, d['site_location'], d['serial_num'])

Похожие вопросы