Сортировка данных в Python по произвольному критерию
Сортировка коллекций по заданному значению является одной из наиболее востребованных операций при обработке данных в Python. С помощью параметра key функций sorted() и list.sort() можно гибко определять критерий упорядочивания элементов. Ниже рассматриваются различные подходы к сортировке по значению, а также типичные ошибки и способы их избегания.
Сортировка по значению в Python
Наиболее эффективный и универсальный способ задать сортировку по произвольному значению - использовать аргумент key. Функция key применяется к каждому элементу и возвращает объект, который будет использоваться для сравнения. Пример со списком кортежей:
data = [(1, 'z'), (2, 'a'), (3, 'm')]
sorted_data = sorted(data, key=lambda x: x[1])
print(sorted_data)Python sort lambda (сортировка с lambda в python)
[(2, 'a'), (3, 'm'), (1, 'z')]
Python сортировка по значению (сортировка по значению в python)
Аргумент reverse=True позволяет изменить порядок на обратный. Такой подход подходит для любых итерабельных объектов, включая списки словарей, строки, пользовательские классы. Важно, что key вызывается однократно для каждого элемента, поэтому вычисления выполняются эффективно.
Типичная ошибка:
попытка передать вkey функцию, которая возвращает значения разных типов (например, int и str) - это вызовет TypeError. Решение: привести значения к одному типу в лямбда-функции или предварительно нормализовать данные.
Как отсортировать список кортежей по второму элементу?
pairs = [(5, 'cat'), (1, 'dog'), (3, 'bird')]
sorted_pairs = sorted(pairs, key=lambda item: item[1])
print(sorted_pairs)
Sorted values python (сортировка значений в python (sorted))
[(3, 'bird'), (5, 'cat'), (1, 'dog')]
Python числа в порядке возрастания (сортировка чисел по возрастанию в python)
Здесь lambda item: item[1] возвращает второй элемент кортежа, по которому и происходит упорядочивание. Если кортежи имеют разную длину, нужно следить за индексами.
Возможная проблема:
если второй элемент - число, записанное как строка («5» vs 5), то сортировка будет лексикографической. Решение: преобразовать тип в key:key=lambda x: int(x[1]).Как отсортировать список словарей по значению конкретного ключа?
users = [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 35}]
sorted_users = sorted(users, key=lambda u: u['age'])
print(sorted_users)
[{'name': 'Bob', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Charlie', 'age': 35}]
Более читаемый вариант - использование operator.itemgetter:
from operator import itemgetter
sorted_users = sorted(users, key=itemgetter('age'))
тот же результат
Ошибка:
если ключ отсутствует в словаре, возникнетKeyError. Для безопасной обработки используйте key=lambda u: u.get('age', 0) или itemgetter с default (доступно в Python 3.10+).Как отсортировать пользовательские объекты по атрибуту?
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'Person({self.name}, {self.age})'
people = [Person('Anna', 28), Person('Ivan', 22), Person('Maria', 30)]
sorted_people = sorted(people, key=lambda p: p.age)
print(sorted_people)
[Person(Ivan, 22), Person(Anna, 28), Person(Maria, 30)]
Для удобства применяется operator.attrgetter:
from operator import attrgetter
sorted_people = sorted(people, key=attrgetter('age'))
Проблема:
если атрибут не определён, возникнетAttributeError. Решение: задать значение по умолчанию через getattr(obj, attr, default) в лямбда-функции.Как отсортировать словарь по значениям?
d = {'a': 3, 'b': 1, 'c': 2}
sorted_items = sorted(d.items(), key=lambda item: item[1])
print(sorted_items)
[('b', 1), ('c', 2), ('a', 3)]
Чтобы получить отсортированный словарь (Python 3.7+):
sorted_dict = dict(sorted(d.items(), key=lambda item: item[1]))
print(sorted_dict)
{'b': 1, 'c': 2, 'a': 3}
Ошибка:
сортировка словаря по значениям работает только с уникальными значениями (при равных значениях порядок не определён). Для устойчивой сортировки можно добавить вторичный ключ.Как отсортировать по нескольким критериям?
data = [('b', 2), ('a', 1), ('b', 1), ('a', 2)]
sorted_data = sorted(data, key=lambda x: (x[0], x[1]))
print(sorted_data)
[('a', 1), ('a', 2), ('b', 1), ('b', 2)]
Порядок полей в кортеже определяет приоритет: первый элемент главный, второй - второстепенный. Можно комбинировать разные типы данных, но они должны быть сравнимы между собой.
Проблема:
если одно из полей -None, сравнение с другими типами вызовет ошибку. Решение: обернуть поле в кортеж с индикатором, например key=lambda x: (x[0] is None, x[0], x[1]).Как отсортировать список на месте?
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort(key=lambda x: -x) # по убыванию
print(numbers)
[9, 5, 4, 3, 1, 1]
Метод list.sort() изменяет исходный список и возвращает None. Он работает только со списками, в отличие от sorted(), который применим к любой итерации.
Типичная ошибка:
случайно присвоить результатlist.sort() переменной (получится None). Всегда используйте sorted() если нужно сохранить исходные данные.Что делать, если среди значений присутствует None?
data = [3, None, 1, None, 2]
sorted_data = sorted(data, key=lambda x: (x is None, x))
print(sorted_data)
[1, 2, 3, None, None]
Кортеж (x is None, x) помещает None в конец (так как True > False). Чтобы поместить None в начало, используйте key=lambda x: (x is not None, x).
Расширенные примеры сортировки по значению
Сортировка строк по длине
words = ['apple', 'kiwi', 'banana', 'cherry', 'mango']
sorted_by_len = sorted(words, key=len)
print(sorted_by_len)
['kiwi', 'apple', 'mango', 'cherry', 'banana']
В качестве ключа передана встроенная функция len. Аналогично можно использовать str.lower для регистронезависимой сортировки.
Сортировка с игнорированием регистра
fruits = ['Apple', 'banana', 'Cherry', 'date']
sorted_ignore_case = sorted(fruits, key=str.lower)
print(sorted_ignore_case)
['Apple', 'banana', 'Cherry', 'date']
Функция str.lower возвращает строку в нижнем регистре, по которой и происходит сравнение.
Сортировка словаря по значениям с получением упорядоченного словаря
scores = {'Math': 90, 'Physics': 85, 'Chemistry': 92, 'Biology': 88}
sorted_scores = dict(sorted(scores.items(), key=lambda item: item[1], reverse=True))
print(sorted_scores)
{'Chemistry': 92, 'Math': 90, 'Biology': 88, 'Physics': 85}
Поскольку в Python 3.7+ словари сохраняют порядок вставки, такой подход удобен для вывода топ-результатов.
Сортировка объектов по вложенному атрибуту
class Company:
def __init__(self, name, employees):
self.name = name
self.employees = employees
companies = [
Company('Alpha', [Person('John', 30), Person('Jane', 25)]),
Company('Beta', [Person('Mike', 35)]),
]
# Сортировка компаний по среднему возрасту сотрудников
def avg_age(company):
return sum(e.age for e in company.employees) / len(company.employees)
sorted_companies = sorted(companies, key=avg_age)
print([c.name for c in sorted_companies])
['Alpha', 'Beta']
Здесь ключ - пользовательская функция, вычисляющая составное значение.
Использование functools.cmp_to_key для нестандартного порядка
from functools import cmp_to_key
def compare(x, y):
# чётные числа идут перед нечётными, затем по возрастанию
if x % 2 == 0 and y % 2 != 0:
return -1
if x % 2 != 0 and y % 2 == 0:
return 1
return (x > y) - (x < y)
numbers = [3, 2, 5, 1, 4, 6]
sorted_custom = sorted(numbers, key=cmp_to_key(compare))
print(sorted_custom)
[2, 4, 6, 1, 3, 5]
Старый способ с cmp заменяется на key везде, где возможно, но для сложной логики сравнения cmp_to_key всё ещё применим.
Сортировка по значению с обработкой None и разными типами
data = [5, 'text', None, 3, 'abc', None]
# Поместить None в конец, строки после чисел (в лексикографическом порядке)
def sort_key(item):
if item is None:
return (1, 0, '')
if isinstance(item, int):
return (0, 0, item)
if isinstance(item, str):
return (0, 1, item)
return (2, 0, str(item))
sorted_data = sorted(data, key=sort_key)
print(sorted_data)
[3, 5, 'abc', 'text', None, None]
Кортежи позволяют задать произвольные категории и порядок внутри них.