- Срезы в Python
- Получение по срезу
- Немного о NumPy
- Удаление по срезу
- Лайфхаки 🙂
- Ключевые выводы
- Срез массива в Python
- Что такое массив
- Как получить доступ к значениям в массиве в Python
- Как получить срез массива в Pyhton
- Срез массива без указания start и stop
- Как получить срез массива, начиная с определенного индекса
- Как взять срез массива до определенного индекса
- Как получить срез массива с индексами start и stop
- Как создать срез с использованием шага
- Отрицательные значения start и stop в срезах
- Как создать срез массива с отрицательным шагом
- Что значит [::-1]
- Заключение
- 2 комментария к “Срез массива в Python”
Срезы в Python
К вашему вниманию гайд по слайсингу (AKA суши-оператор, слайс, срез)! Наверно, все пишущие на питоне знают о синтаксисе вырезания частей последовательности — s[a:b] . Сейчас же мы рассмотрим как самые очевидные, так и менее известные факты об операции получения среза.
(Но прежде чем начнём, нужно уточнить, что в Python как и во многих других языках последний элемент не включается в срезы и диапазоны, что соответствует индексации с нуля. seq[начало:конец:шаг] (Для вычисления данного выражения Python вызывает seq.__getitem__ ) — берёт срез от НАЧАЛО, до КОНЕЦ (не включая его), с шагом ШАГ. По умолчанию НАЧАЛО = 0, КОНЕЦ = длине объекта, ШАГ = 1. Соответственно, какие-нибудь, а возможно и все ( seq[:], поговорим об этом позже ) параметры могут быть опущены).
Получение по срезу
>>> some_str = "Python" >>> some_str[:1] # Задаём конечным индексом 1, а т.к. конец не включается, мы получим первый элемент последовательности ('P'). 'P' >>> PYTH = slice(0, 4) # Вместо того чтоб загромождать код вшитыми диапазонами, мы можем проименовать их (например для упрощения разбора накладной). >>> some_str[PYTH] 'Pyth' >>> some_str[::2] # Шагаем через букву. 'Pto'
Немного о NumPy
Оператор [] может принимать несколько индексов или срезов, разделённых запятыми a[m:n, k:l] . В основном это используется в NumPy для получения двумерного среза и a[i, j] для получения одного элемента двумерного массива. Соответственно для вычисления a[i, j] Python вызывает a.__getitem__((i, j)) . Кстати, т.к. » . » (единственный экземпляр класса ellipsis) распознаётся как лексема, то мы его можем использовать так же и в срезах. Применение этому нашлось в том же NumPy для сокращённого создания среза двумерного массива. Детальнее — https://scipy.github.io/old-wiki/pages/Tentative_NumPy_Tutorial.
Удаление по срезу
Так же мы можем удалять элементы последовательности по срезу с учётом того, что она поддерживает удаление элементов (изменяема))). Приведу пример с рантайм классом SupportsDeletion .
>>> import typing >>> @typing.runtime_checkable >>> class SupportsDeletion(typing.Protocol): >>> def __delitem__(self, key: typing.Any) -> typing.Any: >>> . >>> for builtin_type in (list, dict, str, tuple): >>> print(builtin_type.__name__, "->", isinstance(builtin_type, SupportsDeletion)) list -> True dict -> True str -> False tuple -> False
>>> seq = [1, 2, 3, 4] >>> del seq[:3] # Удаляем первых три элемента последовательности. >>> seq [4]
Лайфхаки 🙂
№1 Можно перевернуть последовательность, если запросить срез seq[::-1]
>>> seq = (1, 2, 3, 4, 5, 6) >>> seq[::-1] (6, 5, 4, 3, 2, 1)
№2 Как удалить все элементы списка с помощью слайса, не разрушая сам обьект-список? (Разумеется, тот же результат можно получить вызвав метод .clear() у списка, но мы же сейчас про слайсы говорим + его нет во второй версии питона).
>>> seq = [1, 2, 3, 4, 5, 6] >>> id(seq) 2071031395200 >>> del seq[:] >>> id(seq) 2071031395200 >>> seq []
№3 Помимо очистки списков, нарезку также можно использовать для замены всех элементов списка, не создавая новый объект-список. Это отличная сокращённая запись для очистки списка и затем повторного его заполнения вручную:
>>> seq = [1, 2, 3, 4, 5, 6, 7] >>> original_list = seq >>> seq[:] = [1, 2, 3] >>> seq [1, 2, 3] >>> original_list [1, 2, 3] >>> original_list is seq True
Приведённый выше пример кода заменил все элементы в seq , но не уничтожил и воссоздал список как таковой. По этой причине старые ссылки на оригинальный объект-список по-прежнему действительны.
№4 Создание мелких копий существующих списков:
>>> seq = [1, 2, 3, 4, 5, 6, 7] >>> copied_list = seq[:] >>> copied_list [1, 2, 3, 4, 5, 6, 7] >>> copied_list is seq False
Создание мелкой копии означает, что копируется только структура элементов, но не сами элементы. Обе копии списка совместно используют одинаковые экземпляры отдельных элементов.
Если же вам необходимо продублировать абсолютно всё, включая и элементы, то необходимо создать глубокую копию списка ( copy.deepcopy(x) ). Для этой цели пригодится встроенный модуль в Python copy.
Ключевые выводы
Слайсы полезны не только для отбора элементов внутри последовательности, а могут также использоваться для очистки, реверсирования и копирования списков.
Срез массива в Python
Давайте разберем, что собой представляют массивы в Python и как взять срез массива. Если вы еще не знакомы с самой концепцией среза, сразу дадим краткое пояснение. Под получением или взятием среза понимается получение определенных значений из уже имеющегося объекта. Например, можно извлечь несколько первых или последних элементов строки или списка. В этой статье мы остановимся на срезах массивов.
Если вы любите смотреть видеоконтент в дополнение к чтению, вот видеоверсия данной статьи.
Что такое массив
Массив – это упорядоченная структура данных, которая позволяет хранить в переменной одновременно несколько элементов одного типа. К каждому из этих элементов можно получить доступ по индексу.
Это несколько похоже на списки (list) в Python. Но списки позволяют хранить элементы различных типов данных. Кроме того, списки сами по себе являются встроенным типом данных, в отличии от массивов.
Как получить доступ к значениям в массиве в Python
Вот синтаксис для создания массива в Python:
import array as arr numbers = arr.array(typecode, [values])
Поскольку тип данных array не встроен в Python по умолчанию, его необходимо загрузить из модуля array. Мы импортируем его под именем arr .
Используя метод array , мы можем создать массив, указав в качестве аргументов typecode (тип данных значений) и [values] , то есть сами значения, которые будут храниться в массиве.
Вот таблица с допустимыми значениями параметра typecode:
TYPECODE | Тип в C | Тип в Python | Размер, байты |
---|---|---|---|
‘b’ | signed char | int | 1 |
‘B’ | unsigned char | int | 1 |
‘u’ | wchar_t | Символ Unicode | 2 |
‘h’ | signed short | int | 2 |
‘H’ | unsigned short | int | 2 |
‘i’ | signed int | int | 2 |
‘I’ | unsigned int | int | 2 |
‘l’ | signed long | int | 4 |
‘L’ | unsigned long | int | 4 |
‘q’ | signed long long | int | 8 |
‘Q’ | unsigned long long | int | 8 |
‘f’ | float | float | 4 |
‘d’ | double | float | 8 |
Значения параметра typecode взяты из документации Python.
Вот пример использования модуля array в Python:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) print(numbers[1]) # 2
Здесь мы создали массив целочисленных значений от 1 до 5. Мы также получили доступ ко второму элементу, используя квадратные скобки и его индекс, который равен 1.
Как получить срез массива в Pyhton
Допустим, вы хотите получить срез массива Python и сохранить результат в новую переменную. Это можно сделать, используя квадратные скобки и двоеточие. Синтаксис будет выглядеть следующим образом:
Параметр start указывает индекс, с которого начинается срез. Его значение по умолчанию равно 0. Параметр stop указывает, до какого индекса продолжается срез. Значение под индексом, указанным как stop , в срез не входит. Параметр step определяет шаг среза. По умолчанию он равен 1.
Давайте рассмотрим несколько примеров, которые иллюстрируют различные способы получения срезов массива.
Срез массива без указания start и stop
Когда вы делаете срез без указания начального и конечного индекса, то получаете точную копию вашего массива:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[:] print(copy) # array('i', [1, 2, 3, 4, 5])
Как видите, мы получили копию массива numbers .
Также стоит отметить, что взятие среза не влияет на исходный массив. Мы только копируем часть исходного массива, в данном случае весь целиком.
Как получить срез массива, начиная с определенного индекса
Например, мы хотим получить срез массива от некоторого начального значения до конца этого массива. Вот как это можно сделать:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[2:] print(copy) # array('i', [3, 4, 5])[2:] означает, что срез берется от индекса 2 (третье значение массива) и до конца массива. Результат это наглядно показывает.
Как взять срез массива до определенного индекса
Например, мы хотим получить срез массива, чтобы в него вошли элементы от первого до третьего. Вот как это можно сделать:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[:3] print(copy) # array('i', [1, 2, 3])[:3] означает, что срез начинается с индекса 0 (поскольку иного индекса не указано) до индекса 3, который задан в явном виде.
Как уже говорилось ранее, в срез не входит значение по индексу 3. Таким образом в результате возвращено значение от 0 до индекса 2 включительно.
Как получить срез массива с индексами start и stop
Допустим, вам нужны элементы массива со второго по четвертый. Вот как это будет выглядеть:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[1:4] print(copy) # array('i', [2, 3, 4])
Два числа, разделенные двоеточием, обозначают начальный и конечный индексы ( start и stop ). В данном случае это были числа 1 и 4. Из результата видно, что срез начинается со значения массива под индексом 1. Это значение равно 2. Заканчивается срез значением, которое идет перед элементом под индексом 4. Оно равно 4, а его индекс равен 3.
Как создать срез с использованием шага
Когда мы указываем значения start и stop 1 и 5 соответственно, то в срез входят значения массива под индексами 1, 2 (приращение 1 здесь и далее), 3 и 4. В данном случае шаг выборки по умолчанию равен 1. Но, что если мы хотим выбирать значения с другим шагом? А вот что:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[1:4:2] print(copy) # array('i', [2, 4])
Добавив еще одно двоеточие, можно задать величину шага ( step ). Теперь наш синтаксис имеет следующий вид: [start:stop:step] .
В нашем примере start – 1, stop – 4 и step – 2. Срез начинается со значения по индексу 1, которое равно 2. Индекс следующего значения получается путем прибавления к индексу первого элемента (1) числа 2 (шаг у нас равен двум), то есть 1 + 2 = 3. Значение по индексу 3 равно 4 и оно добавляется в наш срез. Следующий индекс будет равен 5 (потому что 3 + 2), но так как по такому индексу в исходном массиве никакого значения нет, то далее в срез ничего добавляться не будет.
Как можно заметить, полученный срез включает в себя значения 2 и 4.
Отрицательные значения start и stop в срезах
Значения параметров start и stop могут быть и отрицательными. Отрицательные индексы отсчитываются от конца массива. Это означает, что отрицательный индекс -1 является последним значением в массиве:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) print(numbers[-1]) # 5
Можно заметить, что при вызове значения по индексу -1 мы получили значение 5 – последний элемент массива.
Рассмотрим срез [-3:-1] . Здесь индекс начального элемента равен -3, а конечного -1. Давайте посмотрим? как это будет работать с нашим массивом:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[-3:-1] print(copy) # array('i', [3, 4])
Срез начинается с индекса -3 (это третье значение с конца массива, т.е. 3) и останавливается на индексе -1 (это последнее значение в массиве, 5). Последнее значение в срез не входит, поэтому мы получаем значения 3 и 4.
Сочетание отрицательного начального индекса и положительного конечного индекса (или наоборот) не сработает, так как мы будем пытаться двигаться в разных направлениях одновременно, что невозможно.
Как создать срез массива с отрицательным шагом
Мы можем использовать отрицательные шаги, что означает уменьшение индекса. Вот пример:
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[2::-1] print(copy) # array('i', [3, 2, 1])
Здесь мы указываем в качестве начала среза индекс 2, конец среза не обозначаем и берем шаг равным -1. Таким образом, срез начинается со значения по индексу 2, которое равно 3. Отрицательный шаг означает, что следующее значение в срезе будет иметь индекс меньше предыдущего на 1. То есть индекс следующего значения будет 2 – 1 = 1. По индексу 1 у нас находится значение 2, которое и будет добавлено в наш срез.
Эта процедура будет продолжаться, пока не дойдет до индекса 0. Таким образом наш срез будет содержать значения 3, 2 и 1 (именно в таком порядке).
Что значит [::-1]
Вы когда-нибудь уже видели это выражение в Python? Вот что мы видим: ни начального, ни конечного индекса не указано, только задан отрицательный шаг.
Начальный индекс по умолчанию равен 0, поэтому при использовании шага -1 срез будет содержать значения со следующими индексами: -1 (0 – 1), -2 (-1 – 1), -3 (-2 – 1), -4 (-3 – 1) и -5 (-4 – 1). Смахивает на копию массива в обратном порядке.
import array as arr numbers = arr.array('i', [1, 2, 3, 4, 5]) copy = numbers[::-1] print(copy) # array('i', [5, 4, 3, 2, 1])
Как мы и предполагали, это просто копия массива, записанная в обратном порядке.
Заключение
В этой статье мы кратко рассмотрели, как объявлять массивы в Python, как получить доступ к значениям в массиве, а также как взять срез массива, используя двоеточие и квадратные скобки. Мы разобрали, как создавать срезы с положительными и отрицательными индексами, а также как использовать положительный и отрицательный шаг.