Как сортировать словарь

Словари в Python предназначены для создания пары ключ-значение, доступ к которым осуществляется мгновенно. Что если пришлось итерироваться вокруг словаря? При этом нас волнует порядок, при котором появляются элементы. Тогда первое, что приходит на ум — это сортировать словарь. Итак, в этой статье мы расскажем, как сортировать словарь в Python по ключу и значению.

Начиная с Python 3.6, каждый новый элемент в словаре добавляется в конец

В Python 3.7 словарь упорядочен. Это означает, что при каждом добавлении элемента, он вставляется в конец. Причем, как пишет реализующий это человек, такой механизм на 50% использует меньше памяти и в 2 раза быстрее происходит итерирование [2].

>>> c = {"Alex": 3, "Vera": 6, "Sam": 2}
>>> c["Guy"] = 4
>>> c
{'Alex': 3, 'Vera': 6, 'Sam': 2, 'Guy': 4}

При этом если обновить значение, то ключ останется на том же месте:

>>> c["Sam"] = 7
>>> c
{'Alex': 3, 'Vera': 6, 'Sam': 7, 'Guy': 4}

С удалением пары дело обстоит таким же образом:

>>> c.pop("Vera")
6
>>> c
{'Alex': 3, 'Sam': 7, 'Guy': 4}

Поэтому если вы планируете завести словарь, то оставьте его как есть. Нужно только убедится, что элементы добавляются в том порядке, в котором вы хотите. Например, возьмем CSV-файл с аббревиатурами стран, то вы можете преобразовать его в словарь следующим образом:

>>> import csv
>>> countries = {}
>>> for name, abbr in csv.reader("countries.csv"):
...     countries[name] = abbr
...
>>> countries
>>> {'Afghanistan': 'AFG', 'Albania': 'ALA', 'Alegria': 'DZA', ...}

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

Как сортировать словарь по ключам

Итак, нужно сортировать словарь Python по ключам, как это сделать? Самый простой способ это сделать — вызвать метод items, к которому затем применить функцию sorted. Результатом будет являться список кортежей с парами ключ-значение, поэтому чтобы для преобразования в словарь используется dict.

>>> rooms = {"Pink": "Rm 403", "Space": "Rm 201", "Quail": "Rm 500", "Lime": "Rm 503"}
>>> sorted(rooms.items())
[('Lime', 'Rm 503'), ('Pink', 'Rm 403'), ('Quail', 'Rm 500'), ('Space', 'Rm 201')]
>>> sorted_rooms = dict(sorted(rooms.items()))
>>> sorted_rooms
{'Lime': 'Rm 503', 'Pink': 'Rm 403', 'Quail': 'Rm 500', 'Space': 'Rm 201'}

Но ведь сравниваются кортежи, а не ключи, ведь так?

Список с парами ключ-значение сортируется лексикографически. Это значит, что сортируется по первому элементу, а если они равны, то по второму.

>>> some_tuples = [(1, 3), (3, 1), (1, 9), (0, 3)]
>>> sorted(some_tuples)
[(0, 3), (1, 3), (1, 9), (3, 1)]

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

Также отметим, после сортировки создается новый объект. Обновить словарь, поменяв местами расположение пар, нельзя. Если вам не нужен несортированный словарь, то просто переприсвойте переменную.

Как сортировать словарь по значениям

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

Машинное обучение на Python

Код курса
PYML
Ближайшая дата курса
7 ноября, 2022
Длительность обучения
24 ак.часов
Стоимость обучения
45 000 руб.

Мы можем создать функцию, которая сортирует по второму элементу. Более того, сделаем ее лямбдой (о них говорили тут). Код для такой сортировки в Python выглядит так:

>>> sorted_rooms = dict(sorted(rooms.items(), key=lambda item: item[1]))
>>> sorted_rooms
{'Space': 'Rm 201', 'Pink': 'Rm 403', 'Quail': 'Rm 500', 'Lime': 'Rm 503'}

Или можно воспользоваться функцией itemgetter из модуля operator:

>>> from operator import itemgetter
>>> sorted_rooms = dict(sorted(rooms.items(), key=itemgetter(1)))
>>> sorted_rooms
{'Space': 'Rm 201', 'Pink': 'Rm 403', 'Quail': 'Rm 500', 'Lime': 'Rm 503'}

Какой способ выбрать, зависит от ваших предпочтений.

Сортировка словаря другим образом

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

rooms = {
    "Pink": "Rm 403",
    "Space": "Rm 201",
    "Quail": "Rm 500",
    "Lime": "Rm 503",
    "Ocean": "Rm 2000",
    "Big": "Rm 30",
}

Сортировка по значению не приведет к ожидаемому результату:

>>> from operator import itemgetter
>>> sorted_rooms = dict(sorted(rooms.items(), key=itemgetter(1)))
>>> sorted_rooms
{'Ocean': 'Rm 2000', 'Space': 'Rm 201', 'Big': 'Rm 30', 'Pink': 'Rm 403', 'Quail': 'Rm 500', 'Lime': 'Rm 503'}

Мы ожидаем, что Rm 30 должен стоять самым первым, а Rm 2000 — в конце. Но поскольку мы сортируем строковые значения, то они располагаются в соответствии с символом ASCII (символ 2 стоит раньше 3).

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

def by_room_number(item):
    """Return numerical room given a (name, room_number) tuple."""
    name, room = item
    _, number = room.split()
    return int(number)

sorted_rooms = dict(sorted(rooms.items(), key=by_room_number))

Нужно ли вообще сортировать словари Python?

Когда сортируете словарь, то сначала спросите себя: “нужно ли мне это?”. Или даже конкретнее: “нужен ли мне словарь?”. Словарь “под капотом” содержит обычный массив большого размера, который при необходимости может еще расшириться. Поэтому словари занимает приличное место в памяти. Иногда можно обойтись обычным списком из кортежей, над ним гораздо легче итерироваться и не нужно преобразовывать во что-то другое.

 

О том, как работать с различными структурами данных на реальных примерах из Data Science вы узнаете на наших образовательных курсах в лицензированном учебном центре обучения и повышения квалификации руководителей и ИТ-специалистов (менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data) в Москве:

Источники
  1. Что нового в Python 3.7
  2. Оптимизация словаря

Добавить комментарий

Поиск по сайту