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"]))