Статьи

Как удалять элементы из списков в Python

2025-01-09 14:32 Базовый Python
Удаление элементов из списка в Python — это очень частое действие, которое можно выполнить различными способами. В этом статье мы рассмотрим различные подходы к удалению элементов из списка, как по их позиции, так и по значению, включая использование методов .pop(), del и .remove().

Метод .remove() позволяет удалить первое вхождение указанного значения, тогда как .pop() может удалить элемент по его индексу и вернуть его. Оператор del предоставляет ещё один вариант удаления элементов по индексу, и его также можно использовать для удаления элементов по срезам списка. Выбор подходящего подхода зависит от конкретной задачи.

Чтобы понять всё из этой статьи, следует быть знакомым с основными работы со списками в Python, а именно их созданием, добавлением в них элементов и доступом к элементам по индексу.

Как удалить определенный элемент из списка

Одной из распространенных операций является удаление конкретного элемента из списка. При этом нам может понадобиться потребоваться элемент на основе его позиции в списке или его значения.
Чтобы проиллюстрировать, как можно выполнить эту задачу, предположим, что мы создаем веб-сайт для библиотеки. Наше веб-приложение позволит пользователям сохранять список книг, которые они хотели бы прочитать. Кроме того, оно должно поддерживать редактирование и удаление книг из этого списка, а также его сортировку.
Например, список чтения может выглядеть следующим образом:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
Теперь, когда у нас есть список книг, мы можем несколькими способами удалить одну конкретную. Один из вариантов — использовать метод .pop().

Удаление элементов при помощи метода .pop()

Иногда возникает необходимость удалить элементы из определенной позиции в списке. Например, в нашем приложении-библиотеке пользователи могут отмечать книги для удаления, и приложение будет удалять каждый выбранный элемент, основываясь на его индексе — позиции в списке.
Если мы знаем индекс элемента, который хотим удалить, то можно использовать метод .pop(). Этот метод принимает индекс элемента в качестве необязательного аргумента и затем удаляет и возвращает элемент по этому индексу. Если вы не передаете индекс в вызов метода, то .pop() удалит и вернёт последний элемент в списке.
Важно отметить, что в Python индексация начинается с нуля, то есть первый элемент имеет индекс 0, второй — 1 и так далее. С учетом этого, вот пример использования .pop() для удаления и возврата элемента с индексом ноль в списке книг:
books.pop(0)
Этот вызов удаляет книгу "1984" из списка и возвращает её.
Проверим содержимое списка:
print(books)
# ["Дюна", "Автостопом по галактике", "Война и мир"]
Ещё раз отметим, что .pop() не только удаляет элемент, но и возвращает его значение, которое далее можно использовать для других операций. Предположим, что наше приложение также позволяет пользователям хранить отдельный список книг, которые они прочитали. Как только пользователь прочитал книгу, он может удалить её из исходного списка книг и перенести название в список прочитанных книг:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
read_books = []

read = books.pop(0)
read_books.append(read)

print(read_books)
# ['1984']

print(books)
# ["Дюна", "Автостопом по галактике", "Война и мир"]
Здесь мы создаём новый пустой список read_books для хранения книг, которые пользователь прочитал. Затем методом .pop() удаляем книгу из исходного списка книг и сохраняем её в переменной. Затем используем .append() для добавления этой книги в список read_books.
Если использовать метод .pop() на пустом списке, метод вызовет исключение IndexError:
books = []
books.pop()

Traceback (most recent call last):
  ...
IndexError: pop from empty list
Метод .pop() также вызовет IndexError, если вызвать его с аргументом индекса, который больше размера списка минус один:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
books.pop(50)

Traceback (most recent call last):
  ...
IndexError: pop index out of range
Список книг содержит только четыре элемента, но мы используем .pop() для элемента с индексом 50, но это вне диапазона, что приведёт к ошибке IndexError.
Использование отрицательного индекса в качестве аргумента для .pop() позволяет удалять элементы списка c подсчётом справа налево, а не с начала. Например, индекс -1 соответствует последнему элементу в списке, индекс -2 — предпоследнему и так далее. То есть books[-len(books)] — это отрицательный индекс, который возвращает первый элемент.
Посмотрим пример:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
books.pop(-1)

print(books)
# ["1984", "Дюна", "Автостопом по галактике"]
Тут мы удалили последнюю книгу и проверили результат этой операции. При этом можно было вызвать books.pop() без аргумента, чтобы получить такой же результат.

Удаление элементов при помощи оператора del

Как и метод .pop(), del удаляет элемент по указанной позиции, но не возвращает значение.
Чтобы проиллюстрировать работу del, давайте рассмотрим ситуацию, когда пользователь нашего приложения-библиотеки случайно добавил какие-то книги в список дважды. И вот как правильно использовать del для удаления дублирующихся названий:
books = ["1984", "Дюна", "Дюна", "Автостопом по галактике", "Война и мир"]

del books[2]
print(books)
# ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
Как видим, мы пишем ключевое слово del, затем имя переменной списка, за которым следует нужный индекс в квадратных скобках.
Как и с методом .pop(), тут мы также можем использовать отрицательные индексы:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]

del books[-1]
print(books)
# ["1984", "Дюна", "Автостопом по галактике"]
Тут мы удаляем последний элемент в списке, но del не вернёт значение. Если нам для чего-то нужно сохранить удаленное значение, то стоит использовать .pop().
Как и в .pop(), мы получим исключение IndexError, если попытаемся использовать del с несуществующим в списке индексом:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
del books[100]

Traceback (most recent call last):
  ...
IndexError: list assignment index out of range
Индекс 100 выходит за пределы диапазона, поэтому мы и получим ошибку.
В отличие от .pop(), нам обязательно нужно указать значение индекса при использовании del. Если этого не сделать, то мы получим SyntaxError:
del books[]

File "<input>", line 1
    del books[]
              ^
SyntaxError: invalid syntax
del не удаляет последний элемент в списке, как делает .pop() без аргумента.

Удаление элементов по значению при помощи метода .remove()

Предположим, что в нашем приложении есть текстовое поле, в которое пользователи могут ввести название книги для удаления из списка. Если мы хотим удалить элемент из списка по его значению, а не по индексу, то можно использовать метод .remove(). Этот метод принимает одно значение в качестве аргумента и удаляет первый элемент в списке, который соответствует этому значению:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
books.remove("Дюна")

print(books)
# ["1984", "Автостопом по галактике", "Война и мир"]
Если вызвать .remove() с значением, которого нет в списке, метод вызовет исключение ValueError:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]

books.remove("Жизнь Пи")

Traceback (most recent call last):
  ...
ValueError: list.remove(x): x not in list
Кроме того, в отличие от метода .pop(), мы не сможем вызвать .remove() без аргумента:
books.remove()

Traceback (most recent call last):
  ...
TypeError: list.remove() takes exactly one argument (0 given)

Удаление сразу нескольких элементов из списка

Пользователю может понадобиться удалить несколько элементов из списка за раз. Предположим, что наше приложение-библиотека отображает определенное количество элементов (книг) на странице и позволяет пользователю выбирать и удалять все выбранные элементы.
Если список содержим 25 элементов на странице, пользователю будет быстрее удалить все 25 элементов сразу, как единый блок, чем нажимать и удалять каждый элемент по отдельности.
Для реализации этой задачи можно воспользоваться операторов del, с которым мы познакомились ранее. Он также позволяет удалять из списка сразу срезы. Вместо того чтобы передавать один индекс, мы можем указать начальную позицию среза (включительно) и конечную позицию (не включительно), разделённые двоеточием.
И del удалит все элементы в списке, которые находятся в этом диапазоне индексов. Предположим, что мы хотим удалить первые три книги из списка:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]

del books[0:3]
print(books)
# ['Война и мир']
Здесь мы делаем удаление индексов с 0 по 3, но т.к. указание правой границы берётся не включительно, то по факту удаляются индексы 0, 1, 2. Мы даже могли не указывать левую границу, т.к. она по умолчанию является нулём: del books[0:3].
Для удаления среза можно использовать и отрицательные индексы:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]
del books[-3:-1]

print(books)
# ['1984', 'Война и мир']
Тут мы удаляем книги, начиная с индекса -3 ("Дюна"), и до, но не включая элемент с индексом -1 ("Война и мир"). Эта операция аналогично del books[2:4].

Удаление всех элементов из списка

Представим, что наш пользователь хочет полностью очистить список книг. Можно легко реализовать эту задачу, используя метод .clear(). Вот как это работает:
books = ["1984", "Дюна", "Автостопом по галактике", "Война и мир"]

books.clear()
print(books)
# []
Метод .clear(), который не принимает никаких аргументов и просто удаляет все элементы из списка.

Удаление дубликатов при помощи цикла

Предположим, что мы работаем над приложением, в котором возможны дубликаты записей в списке. Например, приложение для может хранить несколько контактов с одинаковыми номерами телефонов, но разными именами. В таком случае у нас может возникнуть задача удаления дубликатов номеров из списка.
Чтобы решить эту задачу, можно использовать комбинацию цикла и методов списка. Это подразумевает итерацию по списку и удаление каждого элемента, который встречается более одного раза.
Ранее мы уже использовали метод .remove(), который удаляет только первый экземпляр элемента, соответствующего заданному аргументу. Теперь посмотрим, как применить его в цикле.
Для упрощения задачи давайте представим, что ваше приложение для контактов используется в стране с короткими номерами телефонов. Также предположим, что порядок номеров в списке важен. Тогда список контактов может выглядеть следующим образом:
phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]
Сначала нужно определить, сколько раз номер встречается в списке. Для этого в Python есть метод .count(), который возвращает количество вхождений указанного значения в списке.
Например, чтобы узнать, сколько раз в списке контактов встречается номер 54123, можно выполнить следующий код:
phone_numbers.count("54123")
# 3
Теперь пришло время создать цикл для удаления дубликатов. Цикл должен проверять, существует ли более одного экземпляра номера, и удалять каждый дубликат, пока не останется только один:
phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]

for phone_number in phone_numbers[:]:
    while phone_numbers.count(phone_number) > 1:
        phone_numbers.remove(phone_number)

print(phone_numbers)
# ['54123', '54456', '54789']
Тут цикл for проходит по всем номерам в копии исходного списка, а во вложенном цикле while будет вызываться .remove(), удаляя повторы в исходном списке, пока количество конкретного номера больше одного. После цикла в списке дублей не останется. Стоит отметить, что порядок в финальном списке основан на последнем вхождении каждого элемента.
Для более лаконичного способа удаления дубликатов можно воспользоваться словарем. Словарь представляет собой тип данных в Python, который содержит уникальные ключи, сопоставленные со значениями. Поскольку словари не могут содержать дублирующиеся ключи, то можно использовать метод .fromkeys() для удаления копий из вашего списка:
phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]

phone_numbers = list(dict.fromkeys(phone_numbers))
print(phone_numbers)
# ['54123', '54456', '54789']
Здесь метод .fromkeys() преобразования списка в словарь без дублирующихся ключей, а затем этот словарь мы преобразуем обратно в список, который теперь не содержит дубликатов. Словари сохраняют порядок добавления элементов, поэтому элементы в списке без дубликатов будут упорядочены так же, как и в оригинале.

Использование множеств для удаления дубликатов

В предыдущем примере со списком контактов мы условились, что порядок номеров имел значение. Однако, если нам нужно удалить дублирующиеся элементы из списка и порядок элементов не важен, то можно использовать множества. Множество — это такой тип данных в Python, который не допускает наличие в нём дублей.
Рассмотрим пример преобразования списка в множество уникальных номеров телефонов:
phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]

unique_phone_numbers = set(phone_numbers)
print(unique_phone_numbers)
# {'54123', '54789', '54456'}
set() используется для преобразования списка в множество, удаляя все дублирующиеся элементы. Ещё раз отметим, что множества являются неупорядоченными коллекциями, поэтому они не гарантируют, что элементы будут расположены в исходном порядке. Они могут быть не самым подходящим типом данных, если задача требует сохранения порядка элементов.
Однако множества могут быть преобразованы обратно в список и отсортированы. Также операция проверки на вхождения для них более эффективна, это позволит делать более быстрые проверки на то, есть ли какой-то элемент во множестве.

Заключение

Вот мы и изучили различные техники для удаления элементов из списков и узнали как:
  • удалять элементы по индексу при помощи .pop() и del;
  • использовать метод .remove() для удаления первого вхождения указанного значения;
  • удалять удалять срезы при помощи del;
  • удалить все элементы из списка при помощи .clear();
  • удалить дублирующиеся элементы при помощи цикла, словаря и множеств.

Источник: Real Python