Сортировать вложенный словарь по значению, а остаток по другому значению в Python - PullRequest
26 голосов
/ 06 ноября 2010

Рассмотрим этот формат словаря.

{'KEY1':{'name':'google','date':20100701,'downloads':0},
 'KEY2':{'name':'chrome','date':20071010,'downloads':0},
 'KEY3':{'name':'python','date':20100710,'downloads':100}}

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

['KEY3','KEY1','KEY2']

Я уже могу отсортировать список по любому значению, используя sorted, но как мне также отсортировать по второму значению?

Ответы [ 4 ]

39 голосов
/ 06 ноября 2010

Используйте аргумент key для sorted(). Это позволяет вам указать функцию, которая, учитывая фактический сортируемый элемент, возвращает значение, по которому следует отсортировать. Если это значение является кортежем, оно сортируется как сортировка кортежей - по первому значению, а затем по второму.

sorted(your_list, key=lambda x: (your_dict[x]['downloads'], your_dict[x]['date']))
8 голосов
/ 06 ноября 2010

Вы можете передать key функцию в sorted, которая возвращает кортеж, содержащий две вещи, по которым вы хотите отсортировать.Предполагая, что ваш большой словарь называется d:

def keyfunc(tup):
    key, d = tup
    return d["downloads"], d["date"]

items = sorted(d.items(), key = keyfunc)

Вы можете сделать это с lambda, если хотите, но это, вероятно, более понятно.Вот эквивалентный лямбда-код:

items = sorted(d.items(), key = lambda tup: (tup[1]["downloads"], tup[1]["date"]))

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

return -d["downloads"], d["date"]

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

return (-d["downloads"] or sys.maxint), d["date"]
2 голосов
/ 06 ноября 2010

Мой другой ответ был неправильным (как и большинство ответов здесь)

sorted_keys = sorted((key for key in outer_dict if outer_dict[key]['downloads']),
                     key=lambda x: (outer_dict[key]['downloads'],
                                    outer_dict[key]['downloads'])
                     reverse=True)

sorted_keys += sorted((key for key in outer_dict if not outer_dict[key]['downloads']),
                      key=lambda x: outer_dict[key]['date'])

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

Но на самом деле последняя часть ответа Эли Кортрайтс - лучшая.

0 голосов
/ 06 ноября 2010
a = {'KEY1':{'name':'google','date':20100701,'downloads':0},
 'KEY2':{'name':'chrome','date':20071010,'downloads':0},
 'KEY3':{'name':'python','date':20100710,'downloads':100}}


z = a.items()

z.sort(key=lambda x: (x[1]['downloads'], x[1]['date']))
...