Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Модификация списков поэлементно, сортировка, разворачивание Python: Списки

Как вы помните, элементы списков индексированы, т.е. каждый элемент имеет порядковый номер. Первый элемент имеет индекс 0, последний — len(list) - 1.

Функция len возвращает длину списка, но работает она с различными типами, например — со строками и кортежами.

Элементы списка можно получать и заменять через присваивание по их индексу. Если указать отрицательный индекс, то элементы будут браться с конца, и последний элемент списка будет иметь отрицательный индекс -1 (-0, увы, использовать не получится). Вот пара примеров использования индексов со списком:

l = [0] * 3
l[0], l[1] = 10, 32
l[-1] = l[0] + l[1]
print(l)  # => [10, 32, 42]

Обратите внимание, что я создал список клонированием нулей. Так делать безопасно, потому что числа в Python — неизменяемые. Впрочем, все модификации списка я сделал через присваивание, поэтому ничего неожиданного я бы не получил, даже если бы использовал изменяемые объекты.

pop и insert

Итак, получать и заменять элементы по одному мы умеем. Неплохо бы ещё уметь удалять старые элементы и вставлять в середину списка новые. За это отвечают методы pop и insert соответственно. pop удаляет элемент по индексу. Если не указать индекс, то удаляется последний элемент. При этом pop возвращает значение элемента, который удаляет:

l = [1, 2, 3]
l.pop()  # 3
print(l)  # => [1, 2]
l.pop(0)  # 1
print(l)  # => [2]

А вот пример использования insert:

l = [1, 2, 3]
l.insert(1, 100)
print(l)  # => [1, 100, 2, 3]
l.insert(-1, 200)
print(l)  # => [1, 100, 2, 200, 3]

insert всегда вставляет новый элемент перед элементом с указанным индексом относительно начала списка, вне зависимости от того, откуда мы индекс отсчитывали — от начала или от конца. И insert(-1, ..) вставляет элемент перед последним элементом!

Интересно, что l.insert(len(l), x) добавит элемент x в конец списка l, т.е. сработает как l.append(x). Фактически здесь не будет элемента, перед которым будет вставлен новый, вот новый элемент и попадёт в конец списка. Имейте в виду эту особенность, но используйте append, хотя бы потому, что его вызов проще читается!

Ошибки индексации

Если попытаться вызвать pop() у пустого списка или указать индекс за пределами индексов существующих элементов, вы получите ошибку IndexError:

l = []
l.pop()
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# IndexError: pop from empty list

А вот insert более терпим к некорректным индексам и просто добавляет элементы с соответствующего края:

l = [0]
l.insert(-500, 1)
l.insert(1000, 2)
print(l)  # => [1, 0, 2]

Однако полагаться на это не стоит — индексы всё же лучше держать под контролем!

Сортировка и разворачивание

Списки чего-либо периодически приходится сортировать, а иногда и разворачивать. Желательно уметь это делать эффективно. Поэтому список уже имеет встроенные средства для выполнения обеих задач — методы sort и reverse. Оба метода изменяют список по месту (in place). Посмотрим на несколько примеров:

l = [1, 3, 7, 2, 10, 8]
l.sort()
print(l)  # => [1, 2, 3, 7, 8, 10]
l.reverse()
print(l)  # => [10, 8, 7, 3, 2, 1]

Оба метода могут работать без параметров. В случае reverse нечего и параметризовывать: разворачивание — это всегда разворачивание. А вот сортировка может производиться по разным критериям. Если вызывать sort без параметров, то элементы сортируются в порядке возрастания. Однако методу можно передать параметр-функцию, которая будет возвращать критерий сортировки (т.н. ключ или key). Функция будет вызвана по одному разу для каждого элемента списка, после чего элементы будут отсортированы по возрастанию значения ключа. Давайте объявим функцию, которая будет возвращать остаток от деления аргумента на два, и используем её в роли ключа:

def mod2(x):
    return x % 2

l = [1, 2, 3, 6, 5, 4]
l.sort(key=mod2)
print(l)  # => [2, 6, 4, 1, 3, 5]

Обратите внимание, что функцию в метод sort я передал по имени параметра. Такой синтаксис мы рассмотрим позже, но поэкспериментировать с методом sort и разными функциями-ключами вы уже сможете, указывая их по аналогии.

Функция mod2 вернула для чётных и нечётных чисел 0 и 1 соответственно. Поэтому в начале списка оказались сначала чётные числа.

Интересно, что в пределах своей группы числа сохранили порядок: 6 шла в списке перед 4, и это взаимное расположение сохранилось. Умение сохранить относительный порядок элементов, которые уже отсортированы (относительно друг друга) — важная характеристика алгоритма сортировки! Называется она стабильностью, сортировка же в этом случае называется стабильной сортировкой — и в Python сортировка именно такая.

Функция-ключ не обязана возвращать числа — она может возвращать любые значения, которые Python умеет сравнивать. Давайте в предыдущем примере усложним функцию-ключ:

def key(x):
    return (x % 2, x)

l = [1, 2, 3, 6, 5, 4]
l.sort(key=key)
print(l)  # => [2, 4, 6, 1, 3, 5]

Теперь числа разбиты на группы и при этом ещё и отсортированы внутри групп! Когда Python сравнивает кортежи, он сравнивает сначала первые элементы, а если те равны — вторые и т.д. Значения сравниваются, пока не найдётся первое неравенство. Либо пока не кончится один из кортежей — в этом случае более короткий будет "меньше". Вот несколько примеров:

print((1, 2, 3) < (1, 2, 4))  # => True
print((1, 1) < (1, 1, 1))  # => True
print((1, 2) > (1, 1, 1))  # => True
print((3, 4, 5) == (3, 4, 5))  # => True

Домашнее задание

У меня нет цели рассказать про все доступные методы списков, я показываю лишь общие принципы. Я не рассказал про методы count, remove, index: оставляю изучение этих методов вам. Напоминаю, посмотреть документацию можно прямо в REPL с помощью функции help. Только для просмотра информации о методе объекта, нужно передавать метод вместе с объектом: help([].count).


Дополнительные материалы

  1. Стабильная сортировка

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
18 мая 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»