Python: сортировка словаря списков
Продолжаем учиться python (наконец!) и пока не могу полностью обмануть его. То, что я хочу сделать, - сортировать словарь списков по значению, используя третий элемент в списке. Это довольно просто сортировка словаря по значению, когда значение представляет собой только один номер или строку, но этот список вещей меня озадачил.
Пример:
myDict = { 'item1' : [ 7, 1, 9], 'item2' : [8, 2, 3], 'item3' : [ 9, 3, 11 ] }
Я хочу, чтобы иметь возможность итерации через словарь в порядке третьего значения в каждом списке, в этом случае 9, 3, 11.
Большое спасибо за любую помощь!
Ответы
Ответ 1
Вот один из способов сделать это:
>>> sorted(myDict.items(), key=lambda e: e[1][2])
[('item2', [8, 2, 3]), ('item1', [7, 1, 9]), ('item3', [9, 3, 11])]
key
аргумент функции sorted
позволяет получить ключ сортировки для каждого элемента списка.
Чтобы перебрать ключи/значения в этом списке, вы можете использовать что-то вроде:
>>> for key, value in sorted(myDict.items(), key=lambda e: e[1][2]):
... print key, value
...
item2 [8, 2, 3]
item1 [7, 1, 9]
item3 [9, 3, 11]
Ответ 2
Вы указали два совершенно разных желания:
- "Я хочу сделать, это отсортировать словарь списков..."
- "Я хочу, чтобы иметь возможность итерации через словарь в порядке..."
Первое из них по определению невозможно - для сортировки что-то подразумевает перестановку в некотором порядке. Словари Python по своей сути неупорядочены. Второй вариант будет смутно возможен, но вряд ли будет реализован.
Что вы можете сделать, это
- Возьмите копию содержимого словаря (что будет довольно
неупорядоченный)
- Сортировка
- Итерации по отсортированным результатам - и у вас уже есть два
решения для этого. Кстати, решение, в котором вместо этого используется "ключ"
"cmp" лучше; см. sorted
"третий элемент в списке" пахнет "третьим элементом в кортеже" для меня, и "e [1] [2]" просто пахнет:-)... вам может понравиться исследовать использование названных кортежей вместо списков; см. с именем tuple factory
Если вы собираетесь часто делать извлечение/сортировку/процесс на больших наборах данных, вам может понравиться что-то подобное, используя модуль sqlite3, поставляемый Python:
create table ex_dict (k text primary key, v0 int, v1 int, v2 int);
insert into ex_dict values('item1', 7, 1, 9);
-- etc etc
select * from ex_dict order by v2;
Ответ 3
Как сказал Джон Махлин, вы не можете сортировать словарь Python.
Однако вы можете создать индекс ключей, которые могут быть отсортированы в любом порядке.
Предпочтительный шаблон Python (идиома) для сортировки по любому альтернативному критерию называется "украсить-сортировать-undecorate" (DSU). В этой идиоме вы создаете временный список, который содержит кортежи вашего ключа (ов), за которыми следуют ваши исходные элементы данных, а затем вызовите обычный .sort() метод в этом списке (или, в более поздних версиях Python просто оберните украшение в вызываемой функции отсортированной()). Затем вы удаляете "украшения".
Причина, по которой это обычно предпочтительнее, чем передача функции сравнения методу .sort(), заключается в том, что встроенный код сортировки по умолчанию Python (скомпилированный C в обычном C Python) очень быстрый и эффективный в случае по умолчанию, но намного, намного медленнее, когда ему приходится многократно называть код объекта Python, много раз в случае, отличном от стандартного. Поэтому обычно гораздо лучше выполнять итерацию данных, создающих структуры данных, которые могут быть переданы в стандартные процедуры сортировки.
В этом случае вы сможете использовать что-то вроде:
[y[1] for y in sorted([(myDict[x][2], x) for x in myDict.keys()])]
... что понимание списка делает unecorate из отсортированного списка кортежей, который возвращается внутренним пониманием списка. Внутреннее понимание создает набор кортежей, желаемый ключ сортировки (третий элемент списка) и ключ словаря, соответствующий клавише сортировки. myDict.keys() - это, конечно же, метод словарей Python, который возвращает список всех допустимых ключей в любом порядке, который выбирает базовая реализация - предположительно простая итерация по хэшам.
Более подробный способ сделать это может быть легче читать:
temp = list()
for k, v in myDict.items():
temp.append((v[2],))
temp.sort()
results = list()
for i in temp:
results.append(i[1])
Обычно вы должны создавать такой код итеративно, в интерпретаторе, используя небольшие образцы данных. Постройте выражение "украсить" или функцию. Затем оберните это при вызове sorted(). Затем создайте выражение undecorate (которое обычно так же просто, как показано здесь).