Python · Синтаксис · Промежуточный
Сортировка и компараторы
sorted() и list.sort() с функциями key=, reverse и многоключевыми компараторами.
Краткое введение в тему и пояснения перед упражнениями (упражнения ниже):
Ключи-кортежи, operator.itemgetter и многопольная сортировка
#heapq, cmp_to_key и устройство Timsort
#Упражнения:
Сортировка по абсолютному значению
#Напишите функцию, которая принимает список целых чисел и возвращает их отсортированными по абсолютному значению по возрастанию.
def sort_by_abs(numbers):
pass
print(sort_by_abs([-5, 3, -1, 4, -2, 8]))
Решение
def sort_by_abs(numbers):
return sorted(numbers, key=abs)
print(sort_by_abs([-5, 3, -1, 4, -2, 8]))
Сортировка строк без учёта регистра
#Напишите функцию, которая принимает список строк и возвращает их отсортированными по алфавиту без учёта регистра.
def sort_words(words):
pass
print(sort_words(["Banana", "apple", "Cherry", "date"]))
Решение
def sort_words(words):
return sorted(words, key=str.lower)
print(sort_words(["Banana", "apple", "Cherry", "date"]))
Сортировка по фамилии
#Напишите функцию, которая принимает список полных имён (строки вида 'Имя Фамилия') и возвращает их отсортированными по фамилии по алфавиту.
def sort_by_last_name(names):
pass
names = ["Alice Smith", "Bob Johnson", "Carol Adams", "Dave Brown"]
print(sort_by_last_name(names))
Решение
def sort_by_last_name(names):
return sorted(names, key=lambda name: name.split()[-1])
names = ["Alice Smith", "Bob Johnson", "Carol Adams", "Dave Brown"]
print(sort_by_last_name(names))
Сортировка словарей по нескольким полям
#Напишите функцию, которая принимает список словарей продуктов (с ключами 'category' и 'price') и возвращает их отсортированными сначала по категории (А-Я), затем по цене (возрастающей) внутри каждой категории.
def sort_products(products):
pass
products = [
{"name": "Bread", "category": "food", "price": 2},
{"name": "TV", "category": "electronics", "price": 500},
{"name": "Milk", "category": "food", "price": 1},
{"name": "Phone", "category": "electronics", "price": 800},
]
for p in sort_products(products):
print(p)
Решение
def sort_products(products):
return sorted(products, key=lambda p: (p["category"], p["price"]))
products = [
{"name": "Bread", "category": "food", "price": 2},
{"name": "TV", "category": "electronics", "price": 500},
{"name": "Milk", "category": "food", "price": 1},
{"name": "Phone", "category": "electronics", "price": 800},
]
for p in sort_products(products):
print(p)
Сортировка на месте vs возврат нового
#Напишите две функции: одну, которая сортирует список чисел на месте (изменяя оригинал) и возвращает None, и другую, которая возвращает отсортированную копию без изменения оригинала.
def sort_inplace(numbers):
pass
def sort_copy(numbers):
pass
nums = [3, 1, 4, 1, 5]
sort_inplace(nums)
print(nums)
nums2 = [3, 1, 4, 1, 5]
result = sort_copy(nums2)
print(nums2)
print(result)
Решение
def sort_inplace(numbers):
numbers.sort()
def sort_copy(numbers):
return sorted(numbers)
nums = [3, 1, 4, 1, 5]
sort_inplace(nums)
print(nums)
nums2 = [3, 1, 4, 1, 5]
result = sort_copy(nums2)
print(nums2)
print(result)
Топ N
#Напишите функцию, которая принимает список чисел и целое число n, и возвращает n наибольших чисел в порядке убывания.
def top_n(numbers, n):
pass
print(top_n([3, 1, 4, 1, 5, 9, 2, 6, 5, 3], 3))
Решение
def top_n(numbers, n):
return sorted(numbers, reverse=True)[:n]
# Или эффективнее для больших списков:
def top_n(numbers, n):
import heapq
return heapq.nlargest(n, numbers)
print(top_n([3, 1, 4, 1, 5, 9, 2, 6, 5, 3], 3))
Сортировка по частоте
#Напишите функцию, которая принимает список чисел и возвращает их отсортированными по частоте появления — наиболее частые первыми. Элементы с одинаковой частотой должны оставаться в исходном относительном порядке.
def sort_by_frequency(numbers):
pass
print(sort_by_frequency([4, 2, 2, 8, 3, 3, 1, 3]))
Решение
def sort_by_frequency(numbers):
from collections import Counter
freq = Counter(numbers)
return sorted(numbers, key=lambda n: -freq[n])
print(sort_by_frequency([4, 2, 2, 8, 3, 3, 1, 3]))
Стабильность сортировки
#Напишите функцию, которая принимает список кортежей (имя, счёт) и возвращает их отсортированными по счёту по убыванию. При равных счётах сохранить исходный порядок имён (стабильная сортировка).
def rank_players(players):
pass
players = [("Alice", 90), ("Bob", 85), ("Carol", 90), ("Dave", 85)]
print(rank_players(players))
Решение
def rank_players(players):
return sorted(players, key=lambda p: -p[1])
players = [("Alice", 90), ("Bob", 85), ("Carol", 90), ("Dave", 85)]
print(rank_players(players))
Сортировка с разными направлениями
#Напишите функцию, которая принимает список кортежей (имя, возраст) и возвращает их отсортированными по имени по возрастанию и по возрасту по убыванию при равных именах.
def sort_people(people):
pass
people = [("Alice", 30), ("Bob", 25), ("Alice", 25), ("Bob", 35)]
print(sort_people(people))
Решение
def sort_people(people):
return sorted(people, key=lambda p: (p[0], -p[1]))
people = [("Alice", 30), ("Bob", 25), ("Alice", 25), ("Bob", 35)]
print(sort_people(people))
Пользовательская сортировка через functools.cmp_to_key
#Напишите функцию, которая правильно сортирует список строк версий (например '1.10.2', '1.9.0') как номера версий, а не как обычные строки. Используйте functools.cmp_to_key.
from functools import cmp_to_key
def sort_versions(versions):
pass
print(sort_versions(["1.10.2", "1.9.0", "2.0.0", "1.9.10", "1.1.0"]))
Решение
from functools import cmp_to_key
def sort_versions(versions):
def compare(a, b):
a_parts = list(map(int, a.split(".")))
b_parts = list(map(int, b.split(".")))
if a_parts < b_parts: return -1
if a_parts > b_parts: return 1
return 0
return sorted(versions, key=cmp_to_key(compare))
print(sort_versions(["1.10.2", "1.9.0", "2.0.0", "1.9.10", "1.1.0"]))