Функция sorted() в Python. Что передавать в параметр key, возможности функции и примеры использования

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

Когда применяется функция sorted()?

Сортировка данных может выполняться для самых разных задач. Независимо от того, для какой цели используется эта функция, она может принимать в качестве аргумента списки, словари и кортежи. Таким образом, эта функция будет невероятно полезной в случае, если есть большой массив неупорядоченной информации. А спектр применения поистине широк. По сути, работа с любой базой данных не обходится без нее. 

В качестве ориентира для сортировки данных используются значения с ASCII-таблицы. Функция имеет следующие характеристики:

  1. Возвращает список упорядоченных элементов. 
  2. В синтаксисе три параметра – итерируемый объект (то есть, тот набор данных, который упорядочивается), ключ-функция (используется для задания критерия для сортировки) и reverse, которая меняет последовательность сортировки (например, с возрастания на убывание).
  3. Последние два аргумента передавать функции необязательно. Если они не передаются, то сортировка по умолчанию производится по возрастанию.

Параметр key

Теперь следует отметить параметр key, который поможет сделать сортировку полностью персонализированной и очень гибкой. В качестве ключа могут выступать:

  1. Предустановленные функции в Python.
  2. Функции, которые разработал сам пользователь. 
  3. Лямбда-функция.
  4. itemgetter.
  5. attrgetter.

Рассмотрим более подробно, какие бывают ключи. 

Встроенная функция

Встроенные функции могут несколько изменять свое значение, если передаются в качестве аргумента key.

len(). По стандарту предназначена для расчета длины объекта. Если же его использовать в качестве ключа для сортировки, то итерируемый объект будет отсортирован по его длине. 

Внимание: если используется словарь, то сортировка будет осуществляться исключительно по значениям.

Пример:

l1 = {‘carrot’: ‘vegetable’, ‘red’: ‘color’, ‘apple’: ‘fruit’}

print(sorted(l1, key=len))

# Вывод: [‘red’, ‘apple’, ‘carrot’]

abs(). Эта функция возвращает модуль числа (то есть, убирает минус во всех отрицательных числах). Соответственно, если использовать эту функцию в качестве ключа, то основой для сортировки будут модули всех чисел по возрастанию или же, если задается параметр reverse, по убыванию.

l1 = [1, -4, 5, -7, 9, 2]

print(sorted(l1, key=abs))

# Вывод: [1, 2, -4, 5, -7, 9]

str.lower(). Выполняет конвертацию символов, которые находятся в верхнем регистре, в нижний. Соответственно, сортировка списка будет выполняться так, как будто все символы находятся в нижнем регистре (то есть, он не будет учитываться при сортировке, будет простая алфавитная сортировка).

Приведем пример для наглядности. 

s1 = «Hello How are you»

print(sorted(s1.split(), key=str.lower))

# Вывод: [‘are’, ‘Hello’, ‘How’, ‘you’]

Пользовательские функции

Добавление своих функций также возможно. Приведем несколько примеров для наглядности. 

Пример 1. В кортежах элементы по стандарту сортируются, исходя из того, какой первый элемент. Тем не менее, можно осуществить сортировку по второму элементу кортежа. Для этого необходимо объявить функцию, которая будет возвращать его. 

# напишем функцию для получения второго элемента

def sort_key(e):

    return e[1]

l1 = [(1, 2, 3), (2, 1, 3), (11, 4, 2), (9, 1, 3)]

# По умолчанию сортировка выполняется по первому элементу

print(sorted(l1))

# Вывод: [(1, 2, 3), (2, 1, 3), (9, 1, 3), (11, 4, 2)]

# Сортировка по второму элементу с помощью функции sort_key

print(sorted(l1, key=sort_key))

# Вывод: [(2, 1, 3), (9, 1, 3), (1, 2, 3), (11, 4, 2)]

Пример 2. С помощью функций можно выполнять также сортировку объектов класса. Это осуществляется таким образом. Предположим. у нас есть класс Student. Он имеет три атрибута – name, rollno, grade. После этого мы создаем три объекта, которые относятся к классу и добавляем их в список. После этого выполняем сортировку.

Затем объявляется функция sort_key, которая настроена на возвращение атрибута rollno. Соответственно, весь список будет сортироваться по этому значению.

Приведем пример программы, наглядно демонстрирующей, как это работает.

class Student:

    def __init__(self, name, rollno, grade):

        self.name = name

        self.rollno = rollno

        self.grade = grade

    def __repr__(self):

        return f»{self.name}-{self.rollno}-{self.grade}»

 

# Создание объектов

s1 = Student(«Paul», 15, «second»)

s2 = Student(«Alex», 12, «fifth»)

s3 = Student(«Eva», 21, «first»)

s4 = [s1, s2, s3]

 

# Сортировка списка объектов

# Создание функции, которая вернет rollno объекта

def sort_key(s):

    return s.rollno

 

# сортировка списка объектов без ключевого параметра, вызывает TypeError

print(sorted(s4))

# Вывод: TypeError: ‘>’ not supported between instances of ‘Student’ and ‘Student’

 

# Сортировка списка объектов по атрибуту: rollno

s5 = sorted(s4, key=sort_key)

print(s5)

# Вывод: [Alex-12-fifth, Paul-15-second, Eva-21-first]

Лямбда-функция

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

colors = [«Goldenrod», «Purple», «Salmon», «Turquoise», «Cyan»])

 

def normalize_case(string):

    return string.casefold()

 

normalized_colors = map(normalize_case, colors)

После того, как мы используем лямбда-функцию, код станет таким.

colors = [«Goldenrod», «Purple», «Salmon», «Turquoise», «Cyan»])

 

normalized_colors = map(lambda s: s.casefold(), colors)

Такие функции используются для тех ситуаций, когда не нужно использовать переменную, чтобы их передать. Типичный пример – сортировка. Теперь рассмотрим несколько практических примеров использования лямбда-функций.

Пример 1. Лямбда-функция используется для того, чтобы отсортировать список объектов.

class Student:

    def __init__(self, name, rollno, grade):

        self.name = name

        self.rollno = rollno

        self.grade = grade

 

    def __repr__(self):

        return f»{self.name}-{self.rollno}-{self.grade}»

 

# Создание объектов

s1 = Student(«Paul», 15, «second»)

s2 = Student(«Alex», 12, «fifth»)

s3 = Student(«Eva», 21, «first»)

s4 = [s1, s2, s3]

 

# Сортировка списка объектов

# Создание lambda-функции, которая вернет rollno объекта

s5 = sorted(s4, key=lambda x: x.rollno)

print(s5)

# Вывод: [Alex-12-fifth, Paul-15-second, Eva-21-first]

Пример 2. Использование лямбда-функции для возврата второго объекта кортежа и дальнейшей его сортировки по нему.

l1 = [( 1, 2, 3), (3, 1, 1), (8, 5, 3), (3, 4, 2)]

 

# Сортировка по второму элементу в кортеже.

# Lambda-функция возвращает второй элемент в кортеже.

print(sorted(l1, key=lambda x: x[1]))

# Вывод: [(3, 1, 1), (1, 2, 3), (3, 4, 2), (8, 5, 3)]

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

В частности, не нужно использовать лямбда-функции, если уже есть объявленные или существующие функции, выполняющие те же действия.

itemgetter

С помощью itemgetter можно получить несколько объектов (список, кортеж или множество) и вернуть конкретный его элемент.

Давайте попробуем в качестве ключа использовать третий элемент каждого кортежа. Для этого используем itemgetter с индексом 2 (ведь первый элемент считается 0). 

l1 = [( 1, 2, 3), (3, 1, 1), (8, 5, 3), (3, 4, 2)]

 

# Сортировка по второму элементу в кортеже.

# Lambda-функция возвращает второй элемент в кортеже.

print(sorted(l1, key=lambda x: x[1]))

# Вывод: [(3, 1, 1), (1, 2, 3), (3, 4, 2), (8, 5, 3)]

Обратите внимание, что мы импортировали itemgetter из модуля operator.

attrgetter

Позволяет получить кортеж атрибутов или один атрибут и осуществить сортировку по ним.

from operator import attrgetter

 

class Student:

    def __init__(self, name, rollno, grade):

        self.name = name

        self.rollno = rollno

        self.grade = grade

 

    def __repr__(self):

        return f»{self.name}-{self.rollno}-{self.grade}»

 

# Создание объектов

s1 = Student(«Paul», 15, «second»)

s2 = Student(«Alex», 12, «fifth»)

s3 = Student(«Eva», 21, «first»)

s4 = [s1, s2, s3]

 

# Сортировка списка объектов по атрибуту: rollno

s5 = sorted(s4, key=attrgetter(‘rollno’))

print(s5)

# Вывод: [Alex-12-fifth, Paul-15-second, Eva-21-first]

Многоуровневая сортировка

itemgetter также позволяет сортировать по разному количеству элементов на каждом этапе. Например, сначала выполнить сортировку по второму. В случае равенства некоторых объектов – выполнить сортировку по третьему элементу. 

from operator import itemgetter

d = {‘a’: [1, 2, 9], ‘b’: [3, 2, 5], ‘c’: [1, 1, 2]}

# Сортировка по второму, затем по третьему элементу

print(sorted(d.values(), key=itemgetter(1, 2)))

# Вывод: [[1, 1, 2], [3, 2, 5], [1, 2, 9]]

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

Сортировка смешанных типов данных

Частый вопрос: поддерживается ли сортировка смешанных типов данных. К сожалению, нет. Если попробовать отсортировать их, будет выдано исключение TypeError.

Таким образом, сортировка осуществляется по определенному ключу. Следовательно, этот аргумент обязательно передавать функции. В качестве ключа может использоваться любая функция, в том числе, и определенная пользователем. Объект, возвращаемый функцией sorted() – список.

ОфисГуру
Adblock
detector