Работа с подмножествами данных: срезы в Python
Основы работы со срезами списков
Срезы (slice) позволяют извлекать, копировать и изменять подмножества элементов из списка. Основной синтаксис: список[начало:конец:шаг]. Все параметры необязательны и имеют значения по умолчанию: начало = 0, конец = длина списка, шаг = 1. Важно помнить, что элемент с индексом конец не включается в результат.
Базовое использование среза:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sublist = numbers[2:7] # индексы с 2 (включительно) до 7 (исключительно)
print(sublist) # [2, 3, 4, 5, 6]
Python list element (получение элемента списка в python)
[2, 3, 4, 5, 6]
Python add to list (добавление элемента в список)
Здесь start=2, stop=7. В результате получены элементы с индексами 2,3,4,5,6. Если указать только start (numbers[2:]) - получим элементы от индекса 2 до конца. Если только stop (numbers[:5]) - от начала до 5 (не включая 5). Отрицательные индексы отсчитываются от конца списка: numbers[-3:] возвращает последние три элемента.
Как получить первые N элементов списка?
first_three = numbers[:3]
print(first_three) # [0, 1, 2]
Python copy list (копирование списка в python)
[0, 1, 2]
Python list extend (метод extend для списка)
Параметр start опущен, поэтому срез берётся от начала списка.
Проблема: если N больше длины списка, срез вернёт весь список без ошибки. Например, numbers[:20] даст [0,1,...,9]. Это не всегда ожидаемо, если требуется строго N элементов. Следует проверять длину списка или использовать islice из модуля itertools для строгого ограничения.
Как получить последние N элементов списка?
last_three = numbers[-3:] # последние 3 элемента
print(last_three) # [7, 8, 9]
Python list reverse (реверс списка в python)
[7, 8, 9]
Python empty list (создание пустого списка)
Используется отрицательный индекс для start. Параметр stop опущен - до конца списка.
Проблема: если указать start меньше чем -len(list) (например, numbers[-15:]), то срез начнётся с начала списка. Это может быть неочевидно. Аналогично, stop за пределами списка игнорируется.
Как получить каждый второй элемент списка?
every_second = numbers[::2]
print(every_second) # [0, 2, 4, 6, 8]
Python list slice (срезы списков в python)
[0, 2, 4, 6, 8]
Python filter list (фильтрация списка с помощью filter)
Параметр step=2 выбирает элементы с шагом 2. Отрицательный шаг позволяет идти в обратном направлении.
Проблема: при использовании шага, отличного от 1, легко получить пустой список, если диапазон не содержит ни одного элемента (например, numbers[5:2:1] - пусто, так как start > stop при положительном шаге).
Как развернуть список с помощью среза?
reversed_list = numbers[::-1]
print(reversed_list) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Python list function (функции для работы со списками)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Python добавить элемент в массив (добавление элемента в конец списка (append) в python)
Шаг -1 заставляет срез идти от конца к началу. Это простой способ реверсирования списка.
Проблема: создаётся новый список, что может быть неэффективно для больших списков. Для реверсирования на месте следует использовать метод list.reverse().
Как создать копию списка с помощью среза?
copy_list = numbers[:]
print(copy_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
элемент двумерного массива python (доступ к элементу двумерного массива (списка списков) в python)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Python обратиться к элементу списка (обращение к элементу списка по индексу в python)
Полный срез от начала до конца создаёт поверхностную копию списка. Это эквивалентно list(numbers) или numbers.copy().
Проблема: копия является поверхностной - если список содержит изменяемые объекты (например, вложенные списки), их копии не создаются. Изменение во вложенном объекте отразится и в оригинале, и в копии. Для глубокого копирования используйте copy.deepcopy().
Как заменить часть списка другим списком?
numbers = [0,1,2,3,4,5,6,7,8,9]
numbers[2:5] = [100, 200, 300]
print(numbers) # [0, 1, 100, 200, 300, 5, 6, 7, 8, 9]
как заменить элемент в списке python (замена элемента в списке по индексу (list[2] = new_value) в python)
[0, 1, 100, 200, 300, 5, 6, 7, 8, 9]
Присваивание срезу заменяет указанный диапазон элементов. Длина заменяемого диапазона может не совпадать с длиной вставляемого списка - список изменится по длине.
Проблема: при присвоении срезу можно случайно изменить размер списка, что приведёт к ошибкам в коде, рассчитывающем на фиксированное количество элементов. Также можно вставить пустой список ([]) для удаления участка, или наоборот, расширить список.
Расширенные примеры использования срезов
Ниже приведены более сложные и редко встречающиеся применения срезов, которые помогут глубже понять их возможности.
Удаление участка списка с помощью del
numbers = [10,20,30,40,50,60,70]
del numbers[2:5] # удаляем элементы с индекса 2 по 4 (30,40,50)
print(numbers) # [10, 20, 60, 70]
[10, 20, 60, 70]
Оператор del со срезом удаляет указанный диапазон элементов. Это модифицирует исходный список.
Вставка элементов в список через присвоение пустому срезу
numbers = [1,2,5,6]
numbers[2:2] = [3,4] # вставляем элементы начиная с индекса 2, не удаляя существующие
print(numbers) # [1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
Если указать одинаковые start и stop, срез пуст, и присваивание вставляет новый список.
Замена участка с перераспределением длины
numbers = [0,1,2,3,4,5]
numbers[1:4] = [10,20] # заменяем 3 элемента (1,2,3) на 2 элемента (10,20)
print(numbers) # [0, 10, 20, 4, 5]
[0, 10, 20, 4, 5]
Длина списка уменьшилась на 1. Аналогично можно увеличить длину, вставив больше элементов.
Использование переменных в качестве индексов среза
numbers = list(range(20))
start = 5
stop = 15
step = 3
result = numbers[start:stop:step]
print(result) # [5, 8, 11, 14]
[5, 8, 11, 14]
Параметры среза могут быть вычислены заранее или переданы как аргументы. Это удобно при динамическом формировании срезов.
Срезы для строк (аналогично спискам)
text = "Python slicing"
sub = text[7:14] # "slicing"
print(sub) # slicing
slicing
Строки поддерживают те же операции срезов, что и списки, возвращая новую строку.
Проверка палиндрома с помощью среза
def is_palindrome(s):
return s == s[::-1]
print(is_palindrome("radar")) # True
print(is_palindrome("hello")) # False
True False
Срез с шагом -1 даёт перевёрнутую строку. Сравнение с оригиналом определяет палиндром.
Извлечение подсписка из вложенного списка
matrix = [[1,2,3], [4,5,6], [7,8,9]]
row_slice = matrix[1][0:2] # вторая строка, первые два элемента
print(row_slice) # [4, 5]
[4, 5]
Сначала обращаемся к строке по индексу, затем применяем срез к этой строке.
Срез с отрицательным шагом и отрицательными start/stop
numbers = [0,1,2,3,4,5,6,7,8,9]
# элементы с индексами 7,6,5,4,3 (идём от индекса 8 (не вкл) до 3 (вкл) с шагом -2)
result = numbers[-2:-9:-2]
print(result) # [8, 6, 4]
[8, 6, 4]
Понимание направления: при отрицательном шаге start должен быть больше stop, иначе срез будет пуст.
Разбиение списка на части равной длины (chunking)
numbers = list(range(12))
chunk_size = 3
chunks = [numbers[i:i+chunk_size] for i in range(0, len(numbers), chunk_size)]
print(chunks) # [[0,1,2], [3,4,5], [6,7,8], [9,10,11]]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
Генератор списков со срезом - удобный способ разделить список на фрагменты.
Поверхностное копирование многомерного списка (внимание!)
original = [[1,2], [3,4]]
copy = original[:] # поверхностная копия
copy[0][0] = 99
print(original) # [[99,2], [3,4]] - изменилось!
[[99, 2], [3, 4]]
Из-за того, что вложенные списки не копируются, изменение в копии затронуло оригинал. Для глубокого копирования используйте copy.deepcopy(original).
Использование среза для создания нового списка с преобразованием (через генератор)
numbers = [1,2,3,4,5]
# удвоить каждый элемент в срезе [1:4]
squared_slice = [x*2 for x in numbers[1:4]]
print(squared_slice) # [4, 6, 8]
[4, 6, 8]