Типовые задачи с последовательностями в Python [2.6]
Индексация, срезы, преобразования типов последовательностей и сортировка: понятные правила, типовые рецепты и распространённые ошибки. В конце — практические задания и чек‑лист самопроверки.
Последовательности (например, list, tuple, str, range) поддерживают общий набор операций: индексацию s[i], срезы s[start:stop:step] и сортировку (прямо или через преобразование в список).
Содержание
- 1. Цели урока
- 2. Что такое последовательности и что в них “типового”
- 3. Индексация: как доставать элементы
- 4. Срезы (slicing): как брать “кусок” последовательности
- 5. Преобразование типов последовательностей
- 6. Сортировка последовательностей
- 7. Практика: типовые задачи (с решениями)
- 8. Чек‑лист самопроверки знаний (обязательный)
1. Цели урока
- Узнать, как работает индексация и как уверенно доставать элементы.
- Научиться делать срезы (
[start:stop:step]) и понимать их правила. - Познакомиться с преобразованиями между типами последовательностей:
list(),tuple(). - Научиться сортировать: sorted(), list.sort(), key, reverse.
range(start, stop, step), а граница stop никогда не включается.2. Что такое последовательности и что в них “типового”
Последовательность — это упорядоченный набор элементов, у которого обычно есть длина и поддерживается доступ по индексу. К типичным последовательностям относятся: list, tuple, str, range.
lst = [10, 20, 30] # список
tup = (10, 20, 30) # кортеж
s = "python" # строка — тоже последовательность символов
r = range(5) # ленивое "как бы последовательность" чисел
Чем отличаются set и dict
set — неупорядоченная структура: индексации и срезов нет. dict — отображение ключ→значение: доступ идёт по ключу, а не по позиции.
set), то и “кусок по индексам” невозможен.3. Индексация: как доставать элементы
s[i] и базовые правила
Индексация в Python начинается с нуля: s[0] — первый элемент, s[1] — второй и т.д.
arr = ["a", "b", "c", "d"]
print(arr[0]) # a
print(arr[2]) # c
Отрицательные индексы
Отрицательные индексы считаются от конца: -1 — последний элемент, -2 — предпоследний и т.д.
arr = ["a", "b", "c", "d"]
print(arr[-1]) # d
print(arr[-2]) # c
Типовые задачи на индексацию
Задача: первый и последний
arr = [10, 20, 30, 40]
first = arr[0]
last = arr[-1]
print(first, last) # 10 40
Задача: заменить элемент (только list)
arr = [10, 20, 30]
arr[1] = 999
print(arr) # [10, 999, 30]
Кортеж (tuple) неизменяем, так не получится.
Типичные ошибки индексации
Ошибка 1: IndexError — вышли за границы
arr = [1, 2, 3]
# print(arr[3]) # IndexError: list index out of range
arr[3:4] вернёт пустой список вместо ошибки.4. Срезы (slicing): как брать “кусок” последовательности
Синтаксис [start:stop:step]
Срез — это способ получить часть последовательности. Общая форма: [start:stop:step]. Граница stop не включается.
arr = [0, 1, 2, 3, 4, 5]
print(arr[1:4]) # [1, 2, 3] (4 не включается)
print(arr[:3]) # [0, 1, 2]
print(arr[3:]) # [3, 4, 5]
Значения по умолчанию
startпо умолчанию: начало последовательности.stopпо умолчанию: конец последовательности.stepпо умолчанию:1.- Отрицательные значения поддерживаются.
-1в индексации означает “последний элемент”.
range(start, stop, step). Это помогает понимать, какие позиции будут выбраны.Срез со шагом
arr = list(range(10))
print(arr[::2]) # [0, 2, 4, 6, 8]
print(arr[1::2]) # [1, 3, 5, 7, 9]
print(arr[2:9:3]) # [2, 5, 8]
Отрицательный шаг и разворот
Если step отрицательный, срез идёт справа налево. Самый популярный приём — развернуть список: s[::-1].
arr = [1, 2, 3, 4]
print(arr[::-1]) # [4, 3, 2, 1]
Типовые рецепты со срезами
Первые N / последние N
arr = [10, 20, 30, 40, 50]
print(arr[:2]) # [10, 20]
print(arr[-2:]) # [40, 50]
Срезы “мягкие”: если N больше длины, ошибки не будет.
Без первого и последнего
arr = [10, 20, 30, 40, 50]
print(arr[1:-1]) # [20, 30, 40]
Копия списка через срез
a = [1, 2, 3]
b = a[:] # поверхностная копия
print(a, b) # [1, 2, 3] [1, 2, 3]
Срез-присваивание (только list)
Списки изменяемы, поэтому можно заменять “кусок” списка другим набором элементов.
arr = [0, 1, 2, 3, 4, 5]
arr[2:4] = [200, 300, 400]
print(arr)
# [0, 1, 200, 300, 400, 4, 5]
Типичные ошибки со срезами
Ошибка 1: ожидать, что stop включается
arr = [0, 1, 2, 3, 4]
print(arr[1:3]) # [1, 2], а не [1, 2, 3]
Ошибка 2: перепутать границы при отрицательном шаге
arr = [0, 1, 2, 3, 4]
print(arr[1:4:-1]) # [] — идём назад, но stop "не в ту сторону"
print(arr[4:1:-1]) # [4, 3, 2]
step < 0 срез движется справа налево. Указывайте start справа, а stop левее.5. Преобразование типов последовательностей
Конструкторы list(iterable) и tuple(iterable) принимают любой итерируемый объект: список, кортеж, строку, генератор, range и т.д. Они перебирают элементы и создают новую структуру.
print(list("abc")) # ['a', 'b', 'c']
print(tuple([1, 2, 3])) # (1, 2, 3)
print(list(range(5))) # [0, 1, 2, 3, 4]
- Нужна изменяемость — делаем
list(...). - Нужна неизменяемость (например, чтобы использовать как ключ словаря) — делаем
tuple(...). - Нужно “материализовать” ленивый объект (например,
rangeили генератор) — делаемlist(...).
Копирование: a[:] vs list(a)
a = [1, 2, 3]
b1 = a[:] # копия срезом
b2 = list(a) # копия через конструктор
print(b1, b2) # [1, 2, 3] [1, 2, 3]
Типичные ошибки преобразования
Ошибка: ожидать “глубокую” копию
И a[:], и list(a) делают поверхностную копию. Если внутри лежат списки, то вложенные списки будут общими.
a = [[1], [2]]
b = a[:]
b[0].append(999)
print(a) # [[1, 999], [2]] изменилось и в a
6. Сортировка последовательностей
sorted() vs list.sort()
sorted(iterable)принимает итерируемый объект и возвращает новый отсортированный список.list.sort()сортирует сам список на месте и возвращаетNone.
a = [3, 1, 2]
b = sorted(a)
print(a) # [3, 1, 2]
print(b) # [1, 2, 3]
a.sort()
print(a) # [1, 2, 3]
reverse=True
a = [3, 1, 2]
print(sorted(a, reverse=True)) # [3, 2, 1]
Сортировка по ключу: key=...
Аргумент key — функция, которая получает элемент и возвращает “ключ сортировки”. Частый пример: сортировать слова без учёта регистра.
words = ["Python", "java", "Kotlin", "go"]
print(sorted(words, key=str.lower))
# ['go', 'java', 'Kotlin', 'Python']
Стабильность сортировки
Сортировка в Python стабильна: если ключи равны, элементы сохраняют исходный порядок. Это позволяет делать многошаговую сортировку.
data = [("Ann", 20), ("Bob", 20), ("Chris", 19)]
# Сначала сортируем по имени, потом по возрасту:
data_sorted = sorted(data, key=lambda x: x[0])
data_sorted = sorted(data_sorted, key=lambda x: x[1])
print(data_sorted)
# [('Chris', 19), ('Ann', 20), ('Bob', 20)]
Timsort: почему сортировка часто “умная”
Встроенная сортировка Python использует алгоритм Timsort — гибридный подход, сочетающий идеи сортировки вставками и сортировки слиянием. Он хорошо работает на реальных данных, где часто есть частично упорядоченные фрагменты.
sorted() или list.sort(), а не самописные сортировки (самописные полезны для обучения).Типичные ошибки сортировки
Ошибка 1: ждать результат от list.sort()
a = [3, 1, 2]
x = a.sort()
print(x) # None
print(a) # [1, 2, 3]
Ошибка 2: пытаться сортировать “несравнимые” типы
items = [1, "2", 3]
# sorted(items) # TypeError: '<' not supported between instances of 'str' and 'int'
7. Практика: типовые задачи (с решениями)
Задачи на срезы
Задача 1: первые 3, последние 3, без первого и последнего
arr = [10, 20, 30, 40, 50, 60, 70]
print(arr[:3]) # [10, 20, 30]
print(arr[-3:]) # [50, 60, 70]
print(arr[1:-1]) # [20, 30, 40, 50, 60]
Задача 2: каждый 3-й элемент, начиная со второго
arr = list(range(1, 21))
print(arr[1::3])
# [2, 5, 8, 11, 14, 17, 20]
Задачи на индексацию
Задача 3: поменять местами первый и последний элемент (list)
arr = [1, 2, 3, 4, 5]
arr[0], arr[-1] = arr[-1], arr[0]
print(arr) # [5, 2, 3, 4, 1]
Задачи на сортировку
Задача 4: сортировать слова без учёта регистра
words = ["Python", "java", "Kotlin", "go"]
print(sorted(words, key=str.lower))
# ['go', 'java', 'Kotlin', 'Python']
Задача 5: сортировать (name, age) по age, а при равенстве — по name
people = [("Bob", 20), ("Ann", 20), ("Chris", 19), ("Dan", 19)]
# Вариант 1: одним ключом (кортеж ключей)
res1 = sorted(people, key=lambda x: (x[1], x[0]))
print(res1)
# [('Chris', 19), ('Dan', 19), ('Ann', 20), ('Bob', 20)]
# Вариант 2: два прохода, используя стабильность сортировки
res2 = sorted(people, key=lambda x: x[0]) # вторичный ключ
res2 = sorted(res2, key=lambda x: x[1]) # первичный ключ
print(res2)
# [('Chris', 19), ('Dan', 19), ('Ann', 20), ('Bob', 20)]
Задачи на преобразования типов
Задача 6: сделать список из range и развернуть
r = range(1, 6)
lst = list(r)
print(lst) # [1, 2, 3, 4, 5]
print(lst[::-1]) # [5, 4, 3, 2, 1]
8. Чек‑лист самопроверки знаний
Отметьте пункты, которые вы действительно понимаете и можете применить без подсказок.
| ✓ | Навык | Проверка |
|---|---|---|
| Индексация последовательностей | Могу достать первый, последний, предпоследний элементы через s[0], s[-1], s[-2] |
|
| Понимаю границу stop в срезе | Могу объяснить, почему s[1:3] включает индексы 1 и 2, но не 3 |
|
| Срезы со шагом | Могу написать s[::2], s[1::2], s[2:9:3] |
|
| Разворот последовательности | Могу развернуть список/строку через s[::-1] и объяснить, что это отрицательный шаг |
|
| Срез-присваивание | Могу заменить подотрезок списка: arr[2:4] = ... и понимаю, что это работает только для list |
|
| Преобразования типов | Могу преобразовать любой iterable в list() или tuple() |
|
| sorted() vs list.sort() | Могу объяснить, что sorted() возвращает новый список, а sort() сортирует на месте и возвращает None |
|
| Сортировка по ключу | Могу сортировать без учёта регистра через key=str.lower или сортировать кортежи по полям |
|
| Стабильность сортировки | Могу сделать многошаговую сортировку (вторичный ключ, затем первичный) и понимаю, почему порядок сохраняется |