← Назад к вопросам

Зачем нужны ключи в списках?

1.0 Junior🔥 71 комментариев
#Другое

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Назначение ключей (key) в функциях работы со списками

Параметр key в функциях сортировки и поиска позволяет задать критерий, по которому сравниваются элементы, не изменяя сами элементы. Это один из самых мощных инструментов Python для работы со списками.

Основной концепт

Проблема

# Нужно отсортировать студентов по имени
students = [("Alice", 25), ("Bob", 20), ("Charlie", 23)]

# Без key: сортирует по первому элементу кортежа
sorted_students = sorted(students)
print(sorted_students)
# [('Alice', 25), ('Bob', 20), ('Charlie', 23)]
# Работает, но по алфавиту имён

# Нужно отсортировать по возрасту (второй элемент)
# Как это сделать? 👇

Решение: key parameter

students = [("Alice", 25), ("Bob", 20), ("Charlie", 23)]

# Указываем функцию, которая извлекает значение для сравнения
sorted_by_age = sorted(students, key=lambda x: x[1])
print(sorted_by_age)
# [('Bob', 20), ('Charlie', 23), ('Alice', 25)]
# Отсортировано по возрасту!

Где используется key

1. sorted() — сортировка

# Пример 1: сортировка строк по длине
words = ["apple", "pie", "python", "code"]
sorted_by_length = sorted(words, key=len)
print(sorted_by_length)
# ['pie', 'code', 'apple', 'python']

# Пример 2: сортировка словарей по значению
users = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78},
]

sorted_by_score = sorted(users, key=lambda user: user['score'], reverse=True)
print(sorted_by_score)
# [{"name": "Bob", "score": 92}, ...]

# Пример 3: естественная сортировка файлов
files = ["file1.txt", "file10.txt", "file2.txt"]

# Неправильно (лексикографическая сортировка)
wrong_sort = sorted(files)
print(wrong_sort)
# ['file1.txt', 'file10.txt', 'file2.txt']

# Правильно (естественная сортировка)
import re

def natural_sort_key(text):
    return [int(c) if c.isdigit() else c for c in re.split(r'(\d+)', text)]

correct_sort = sorted(files, key=natural_sort_key)
print(correct_sort)
# ['file1.txt', 'file2.txt', 'file10.txt']

2. list.sort() — сортировка на месте

# sorted() возвращает новый список
# list.sort() изменяет список на месте (экономит память)

scores = [5, 2, 8, 1, 9]
scores.sort()  # Изменяет список на месте
print(scores)  # [1, 2, 5, 8, 9]

scores.sort(reverse=True)  # По убыванию
print(scores)  # [9, 8, 5, 2, 1]

# С key
products = [
    {"name": "Laptop", "price": 1200},
    {"name": "Mouse", "price": 20},
    {"name": "Monitor", "price": 300},
]

products.sort(key=lambda p: p['price'])
for product in products:
    print(f"{product['name']}: ${product['price']}")
# Mouse: $20
# Monitor: $300
# Laptop: $1200

3. max() и min() — поиск максимума/минимума

# Найти студента с наибольшей оценкой
students = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78},
]

top_student = max(students, key=lambda s: s['score'])
print(f"Top student: {top_student['name']} with score {top_student['score']}")
# Top student: Bob with score 92

# Найти слово с максимальной длиной
words = ["python", "programming", "code", "development"]
longest = max(words, key=len)
print(f"Longest word: {longest}")
# Longest word: development

# Найти продукт с минимальной ценой
products = [
    {"name": "Laptop", "price": 1200},
    {"name": "Mouse", "price": 20},
    {"name": "Monitor", "price": 300},
]

cheapest = min(products, key=lambda p: p['price'])
print(f"Cheapest: {cheapest['name']} at ${cheapest['price']}")
# Cheapest: Mouse at $20

4. Встроенная функция в sorted

# sorted() использует key для каждого элемента

# Сортировка по нескольким критериям
students = [
    {"name": "Alice", "grade": "A", "score": 85},
    {"name": "Bob", "grade": "A", "score": 92},
    {"name": "Charlie", "grade": "B", "score": 88},
]

# Сначала по оценке, потом по баллам
sorted_students = sorted(
    students, 
    key=lambda s: (s['grade'], -s['score'])  # Кортеж как ключ
)

for student in sorted_students:
    print(f"{student['name']}: {student['grade']} ({student['score']})")
# Bob: A (92)
# Alice: A (85)
# Charlie: B (88)

Практические примеры

Пример 1: Сортировка объектов из БД

from dataclasses import dataclass
from datetime import datetime

@dataclass
class Post:
    id: int
    title: str
    created_at: datetime
    likes: int

posts = [
    Post(1, "Python Tips", datetime(2024, 1, 15), 50),
    Post(2, "Django Tutorial", datetime(2024, 2, 10), 120),
    Post(3, "FastAPI Guide", datetime(2024, 1, 20), 85),
]

# Сортировка по дате (новые сверху)
recent_posts = sorted(posts, key=lambda p: p.created_at, reverse=True)
for post in recent_posts:
    print(f"{post.title} ({post.created_at.date()})")
# Django Tutorial (2024-02-10)
# FastAPI Guide (2024-01-20)
# Python Tips (2024-01-15)

# Сортировка по лайкам
popular_posts = sorted(posts, key=lambda p: p.likes, reverse=True)
for post in popular_posts:
    print(f"{post.title} ({post.likes} likes)")
# Django Tutorial (120 likes)
# FastAPI Guide (85 likes)
# Python Tips (50 likes)

Пример 2: Кейс-инсензитивная сортировка

# Проблема: обычная сортировка регистрозависима
names = ["alice", "Bob", "charlie", "David"]
wrong_sort = sorted(names)
print(wrong_sort)
# ['Bob', 'David', 'alice', 'charlie']  # Заглавные первыми!

# Решение: используйте key=str.lower
correct_sort = sorted(names, key=str.lower)
print(correct_sort)
# ['alice', 'Bob', 'charlie', 'David']  # Правильно!

Пример 3: Сортировка с преобразованием

# Сортировка ISO дат как строк
date_strings = ["2024-03-15", "2024-01-10", "2024-02-20"]

# Неправильно (как строки)
wrong = sorted(date_strings)
print(wrong)
# ['2024-01-10', '2024-02-20', '2024-03-15']  # Работает, но медленно

# Правильно (используем key для преобразования)
from datetime import datetime

correct = sorted(
    date_strings,
    key=lambda d: datetime.strptime(d, '%Y-%m-%d')
)
print(correct)
# ['2024-01-10', '2024-02-20', '2024-03-15']

Пример 4: Сортировка по методу класса

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def get_priority(self):
        # VIP if age > 50
        return 0 if self.age > 50 else 1
    
    def __repr__(self):
        return f"User({self.name}, {self.age})"

users = [
    User("Alice", 30),
    User("Bob", 55),
    User("Charlie", 28),
    User("David", 60),
]

# Сортировка по методу
vip_first = sorted(users, key=lambda u: u.get_priority())
for user in vip_first:
    print(user)
# User(Bob, 55)
# User(David, 60)
# User(Alice, 30)
# User(Charlie, 28)

Пример 5: Сложная сортировка для поиска

from operator import itemgetter, attrgetter

# Способ 1: через lambda
data = [
    {"category": "A", "priority": 1, "name": "Task 1"},
    {"category": "B", "priority": 2, "name": "Task 2"},
    {"category": "A", "priority": 3, "name": "Task 3"},
]

sorted_data = sorted(
    data,
    key=lambda x: (x['category'], x['priority'])
)

# Способ 2: через itemgetter (быстрее!)
sorted_data = sorted(data, key=itemgetter('category', 'priority'))

for item in sorted_data:
    print(f"{item['category']}-{item['priority']}: {item['name']}")
# A-1: Task 1
# A-3: Task 3
# B-2: Task 2

Производительность

import timeit

data = list(range(10000, 0, -1))

# Lambda
t1 = timeit.timeit(
    lambda: sorted(data, key=lambda x: -x),
    number=100
)

# operator.itemgetter (быстрее для simple extraction)
t2 = timeit.timeit(
    lambda: sorted(data, key=lambda x: -x),
    number=100
)

print(f"Lambda: {t1:.4f}s")
print(f"Itemgetter: {t2:.4f}s")

# itemgetter обычно быстрее на 20-30% для простых операций

Лучшие практики

# ✅ Используйте key для:
# - Сортировки по полям объектов
# - Кейс-инсензитивной сортировки
# - Сортировки по производным значениям
# - Поиска max/min по критерию

# ❌ Не делайте:
# - Не сортируйте внутри key (будет медленно)
# - Не вызывайте дорогие функции в key
# - Не используйте side effects в key

# Плохо
bad_key = lambda x: do_expensive_calculation(x)

# Хорошо
good_key = lambda x: x.field  # Простое извлечение значения

Вывод

Параметр key — это мощный механизм для определения критериев сравнения в Python. Правильное использование key делает код:

  • Более читаемым
  • Более гибким
  • Более производительным

Это essential skill для написания clean и efficient Python кода при работе со списками и поиском.