Python 3: индексы и срезы строк
На самом деле в Python строка представляются как упорядоченная коллекция символов. И ключевое слово здесь – «упорядоченная». Это значит, что у каждого символа в строке есть свой порядковый номер – индекс, по которому мы можем его получить. Например, когда мы создаем строку
то формируется следующая коллекция:
Каждый символ имеет свой индекс, начиная с нулевого. Первый символ в Python всегда имеет нулевой индекс.
Для обращения к тому или иному символу используется следующий синтаксис:
<строка>[<индекс>]
Например:
и так далее. Но, если указать неверный индекс, например:
то возникнет ошибка. Поэтому здесь следует быть аккуратным и не выходить за пределы этого списка. В частности, последний «рабочий» индекс можно определить с помощью функции len – длины строки:
lastIndex = len(<строка>) – 1
То есть, к последнему индексу мы можем обратиться так:
Но это не очень удобно. Поэтому разработчики языка Python решили, что отрицательные индексы будут означать движение по строке с конца в начало. И предыдущую запись можно переписать так:
Видите? Это намного удобнее. То есть, у строк есть еще такие отрицательные индексы:
Также в Python можно использовать доступ к отдельному символу непосредственно у строкового литерала:
Иногда это бывает удобно.
Срезы
Часто в программировании требуется выбрать не один какой-то символ, а сразу несколько. Для этого используются так называемые срезы. Их работу проще показать на конкретных примерах. Пусть у нас есть наша строка:
и мы хотим выделить последнее слово «World!». Для этого в квадратных скобках указывается начальный индекс и через двоеточие – конечный. Если мы запишем все вот в таком виде:
то получим результат «World» без восклицательного знака. Дело в том, что последний индекс исключается из интервала, то есть, интервал определяется как
[6: 11)
Поэтому, мы должны записать срез так:
Другой пример для выделения символов «llo»:
и так далее. В Python допускается не указывать начальное или конечное значения, или даже, оба из них. Например:
выделяет слово «Hello», а вот так:
получим «World!». Наконец, записав все в таком виде:
получим ту же самую строку, не копию! Это можно проверить так:
copy = msg[:] print(id(copy), id(msg))
Увидим одно и то же значение id для обеих переменных, это означет, что они ссылаются на один и тот же объект.
В срезах на Python можно дополнительно указывать шаг через двоеточие. Например, так:
мы здесь ставим еще одно двоеточие и указываем шаг 2, то есть, идем через символ: «HloWrd». Также это можно комбинировать с граничными значениями:
msg[:5:2] msg[6::2] msg[1:6:2]
и использовать отрицательный шаг:
в этом случае символы будут перебираться в обратном порядке.
Строка – неизменяемый объект
Далее, при работе со строками следует помнить, что это неизменяемый объект, то есть, мы не можем изменять в строковом объекте уже существующие символы, то есть, вот такая запись:
приведет к ошибке, говорящая о том, что строка не может быть изменена. Тогда как в Python нам изменять строки? Для этого создается новая строка с нужным содержимым. Например, изменим строку
«Hello World!»
на строку
«Hello word!»
Это можно сделать так:
myStr = msg[:6]+"w"+msg[7:9]+msg[10:]
В результате строка myStr ссылается на новую измененную строку, а msg осталась прежней.
Задания для самоподготовки
1. Напишите программу подсчета букв ‘a’ в строке «abrakadabra».
2. Из строки «abrakadabra» удалите все сочетания «ab».
3. Напишите программу определения слова палиндрома (это слова, которые одинаково читаются в обоих направлениях, например, анна, abba и т.п.). Слово вводится с клавиатуры.
4. Напишите программу определения количества вхождений фраз «ra» в слове «abrakadabra».
5. Разделите введенное с клавиатуры предложение на слова (слова разделяются пробелом).
Индексы и срезы | Python 3 для начинающих и чайников
Сегодня мы поговорим об операциях взятия индекса и среза.
Взятие элемента по индексу
Как и в других языках программирования, взятие по индексу:
>>> a = [1, 3, 8, 7] >>> a[0] 1 >>> a[3] 7 >>> a[4] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
Как и во многих других языках, нумерация элементов начинается с нуля. При попытке доступа к несуществующему индексу возникает исключение IndexError.
В данном примере переменная a являлась списком, однако взять элемент по индексу можно и у других типов: строк, кортежей.
В Python также поддерживаются отрицательные индексы, при этом нумерация идёт с конца, например:
>>> a = [1, 3, 8, 7] >>> a[-1] 7 >>> a[-4] 1 >>> a[-5] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
Срезы
В Python, кроме индексов, существуют ещё и срезы.
item[START:STOP:STEP] — берёт срез от номера START, до STOP (не включая его), с шагом STEP. По умолчанию START = 0, STOP = длине объекта, STEP = 1. Соответственно, какие-нибудь (а возможно, и все) параметры могут быть опущены.
>>> a = [1, 3, 8, 7] >>> a[:] [1, 3, 8, 7] >>> a[1:] [3, 8, 7] >>> a[:3] [1, 3, 8] >>> a[::2] [1, 8]
Также все эти параметры могут быть и отрицательными:
>>> a = [1, 3, 8, 7] >>> a[::-1] [7, 8, 3, 1] >>> a[:-2] [1, 3] >>> a[-2::-1] [8, 3, 1] >>> a[1:4:-1] []
В последнем примере получился пустой список, так как START < STOP, а STEP отрицательный. То же самое произойдёт, если диапазон значений окажется за пределами объекта:
>>> a = [1, 3, 8, 7] >>> a[10:20] []
Также с помощью срезов можно не только извлекать элементы, но и добавлять и удалять элементы (разумеется, только для изменяемых последовательностей).
>>> a = [1, 3, 8, 7] >>> a[1:3] = [0, 0, 0] >>> a [1, 0, 0, 0, 7] >>> del a[:-3] >>> a [0, 0, 7]
Интерактивный учебник языка Python
1. Строки
Строка считывается со стандартного ввода функцией input()
. Напомним,
что для двух строк определена операция сложения (конкатенации), также определена
операция умножения строки на число.
Строка состоит из последовательности символов. Узнать количество символов (длину строки)
можно при помощи функции len
.
Любой другой объект в Питоне можно перевести к строке, которая ему соответствует.
Для этого нужно вызвать функцию str()
, передав ей в качестве параметра объект,
переводимый в строку.
На самом деле каждая строка, с точки зрения Питона, — это объект
класса str. Чтобы получить по объекту другой объект другого класса, как-то ему соответствующий,
можно использовать функцию приведения. Имя этой функции совпадает с именем класса, к которому мы приводим объект.
(Для знатоков: эта функция — это конструктор объектов данного класса.) Пример: int — класс
для целых чисел. Перевод строки в число осуществляется функцией int()
.
What is the answer? 42
s = input() print(len(s)) t = input() number = int(t) u = str(number) print(s * 3) print(s + ' ' + u)
2. Срезы (slices)
Срез (slice) — извлечение из данной строки одного символа или некоторого фрагмента подстроки или подпоследовательности.
Есть три формы срезов. Самая простая форма среза: взятие одного символа
строки, а именно, S[i]
— это срез, состоящий из одного символа,
который имеет номер i
. При этом считается, что нумерация начинается
с числа 0. То есть если S = 'Hello'
, то S[0] == 'H'
,
, S[2] == 'l'
, S[3] == 'l'
, S[4] == 'o'
.
Заметим, что в Питоне нет отдельного типа для символов строки. Каждый объект, который получается
в результате среза S[i]
— это тоже строка типа str.
Номера символов в строке (а также в других структурах данных: списках, кортежах) называются индексом.
Если указать отрицательное значение индекса, то номер будет отсчитываться
с конца, начиная с номера -1
. То есть S[-1] == 'o'
, S[-2] == 'l'
, S[-3] == 'l'
, S[-4] == 'e'
, S[-5] == 'H'
.
Или в виде таблицы:
Строка S | H | e | l | l | o |
Индекс | S[0] | S[1] | S[2] | S[3] | S[4] |
Индекс | S[-5] | S[-4] | S[-3] | S[-2] | S[-1] |
Если же номер символа в срезе строки S
больше либо равен len(S)
,
или меньше, чем -len(S)
, то при обращении к этому символу строки произойдет
ошибка IndexError: string index out of range
.
Срез с двумя параметрами: S[a:b]
возвращает подстроку из b - a
символов,
начиная с символа c индексом a
,
то есть до символа с индексом b, не включая его.
Например, S[1:4] == 'ell'
, то же самое получится
если написать S[-4:-1]
. Можно использовать как положительные,
так и отрицательные индексы в одном срезе, например, S[1:-1]
—
это строка без первого и последнего символа (срез начинается с символа с индексом 1 и
заканчиватеся индексом -1, не включая его).
При использовании такой формы среза ошибки IndexError
никогда не возникает. Например, срез S[1:5]
вернет строку 'ello'
, таким же будет результат,
если сделать второй индекс очень большим, например, S[1:100]
(если в строке не более 100 символов).
Если опустить второй параметр (но поставить двоеточие),
то срез берется до конца строки. Например, чтобы удалить
из строки первый символ (его индекс равен 0), можно
взять срез S[1:]
. Аналогично
если опустить первый параметр, то можно взять срез от начала строки.
То есть удалить из строки последний символ можно при помощи среза S[:-1]
. Срез S[:]
совпадает с самой строкой S
.
Любые операции среза со строкой создают новые строки и никогда не меняют исходную строку. В Питоне строки вообще являются неизменяемыми, их невозможно изменить. Можно лишь в старую переменную присвоить новую строку.
На самом деле в питоне нет и переменных. Есть лишь имена, которые связаны с какими-нибудь объектами. Можно сначала связать имя с одним объектом, а потом — с другим. Можно несколько имён связать с одним и тем же объектом.
Если задать сре
индексирование, срезы, сортировка / Хабр
Данная статья является продолжением моей статьи «Python: коллекции, часть 1: классификация, общие подходы и методы, конвертация».В данной статье мы продолжим изучать общие принципы работы со стандартными коллекциями (модуль collections в ней не рассматривается) Python.
Для кого: для изучающих Python и уже имеющих начальное представление о коллекциях и работе с ними, желающих систематизировать и углубить свои знания, сложить их в целостную картину.
ОГЛАВЛЕНИЕ:
- Индексирование
- Срезы
- Сортировка
1. Индексирование
1.1 Индексированные коллекции
Рассмотрим индексированные коллекции (их еще называют последовательности — sequences) — список (list), кортеж (tuple), строку (string).
Под индексированностью имеется ввиду, что элементы коллекции располагаются в определённом порядке, каждый элемент имеет свой индекс от 0 (то есть первый по счёту элемент имеет индекс не 1, а 0) до индекса на единицу меньшего длины коллекции (т.е. len(mycollection)-1).
1.2 Получение значения по индексу
Для всех индексированных коллекций можно получить значение элемента по его индексу в квадратных скобках. Причем, можно задавать отрицательный индекс, это значит, что будем находить элемент с конца считая обратном порядке.
При задании отрицательного индекса, последний элемент имеет индекс -1, предпоследний -2 и так далее до первого элемента индекс которого равен значению длины коллекции с отрицательным знаком, то есть (-len(mycollection).
элементы | a | b | c | d | e |
---|---|---|---|---|---|
индексы | 0 (-5) | 1 (-4) | 2 (-3) | 3 (-2) | 4 (-1) |
my_str = "abcde"
print(my_str[0]) # a - первый элемент
print(my_str[-1]) # e - последний элемент
print(my_str[len(my_str)-1]) # e - так тоже можно взять последний элемент
print(my_str[-2]) # d - предпоследний элемент
Наши коллекции могут иметь несколько уровней вложенности, как список списков в примере ниже. Для перехода на уровень глубже ставится вторая пара квадратных скобок и так далее.
my_2lvl_list = [[1, 2, 3], ['a', 'b', 'c']]
print(my_2lvl_list[0]) # [1, 2, 3] - первый элемент — первый вложенный список
print(my_2lvl_list[0][0]) # 1 — первый элемент первого вложенного списка
print(my_2lvl_list[1][-1]) # с — последний элемент второго вложенного списка
1.3 Изменение элемента списка по индексу
Поскольку кортежи и строки у нас неизменяемые коллекции, то по индексу мы можем только брать элементы, но не менять их:
my_tuple = (1, 2, 3, 4, 5)
print(my_tuple[0]) # 1
my_tuple[0] = 100 # TypeError: 'tuple' object does not support item assignment
А вот для списка, если взятие элемента по индексу располагается в левой части выражения, а далее идёт оператор присваивания =, то мы задаём новое значение элементу с этим индексом.
my_list = [1, 2, 3, [4, 5]]
my_list[0] = 10
my_list[-1][0] = 40
print(my_list) # [10, 2, 3, [40, 5]]
UPD: Примечание: Для такого присвоения, элемент уже должен существовать в списке, нельзя таким образом добавить элемент на несуществующий индекс.
my_list = [1, 2, 3, 4, 5]
my_list[5] = 6 # IndexError: list assignment index out of range
2 Срезы
2.1 Синтаксис среза
Очень часто, надо получить не один какой-то элемент, а некоторый их набор ограниченный определенными простыми правилами — например первые 5 или последние три, или каждый второй элемент — в таких задачах, вместо перебора в цикле намного удобнее использовать так называемый срез (slice, slicing).
Следует помнить, что взяв элемент по индексу или срезом (slice) мы не как не меняем исходную коллекцию, мы просто скопировали ее часть для дальнейшего использования (например добавления в другую коллекцию, вывода на печать, каких-то вычислений). Поскольку сама коллекция не меняется — это применимо как к изменяемым (список) так и к неизменяемым (строка, кортеж) последовательностям.
Синтаксис среза похож на таковой для индексации, но в квадратных скобках вместо одного значения указывается 2-3 через двоеточие:
my_collection[start:stop:step] # старт, стоп и шаг
Особенности среза:
Примеры срезов в виде таблицы:
Код примеров из таблицы
col = 'abcdefg'
print(col[:]) # abcdefg
print(col[::-1]) # gfedcba
print(col[::2]) # aceg
print(col[1::2]) # bdf
print(col[:1]) # a
print(col[-1:]) # g
print(col[3:4]) # d
print(col[-3:]) # efg
print(col[-3:1:-1]) # edc
print(col[2:5]) # cde
2.2. Именованные срезы
Чтобы избавится от «магических констант», особенно в случае, когда один и тот же срез надо применять многократно, можно задать константы с именованными срезами с пользованием специальной функции slice()()
Примечание: Nonе соответствует опущенному значению по-умолчанию. То есть [:2] становится slice(None, 2), а [1::2] становится slice(1, None, 2).
person = ('Alex', 'Smith', "May", 10, 1980)
NAME, BIRTHDAY = slice(None, 2), slice(2, None)
# задаем константам именованные срезы
# данные константы в квадратных скобках заменятся соответствующими срезами
print(person[NAME]) # ('Alex', 'Smith')
print(person[BIRTHDAY]) # ('May', 10, 1980)
my_list = [1, 2, 3, 4, 5, 6, 7]
EVEN = slice(1, None, 2)
print(my_list[EVEN]) # [2, 4, 6]
2.3 Изменение списка срезом
Важный момент, на котором не всегда заостряется внимание — с помощью среза можно не только получать копию коллекции, но в случае списка можно также менять значения элементов, удалять и добавлять новые.
Проиллюстрируем это на примерах ниже:
- Даже если хотим добавить один элемент, необходимо передавать итерируемый объект, иначе будет ошибка TypeError: can only assign an iterable
my_list = [1, 2, 3, 4, 5] # my_list[1:2] = 20 # TypeError: can only assign an iterable my_list[1:2] = [20] # Вот теперь все работает print(my_list) # [1, 20, 3, 4, 5]
- Для вставки одиночных элементов можно использовать срез, код примеров есть ниже, но делать так не рекомендую, так как такой синтаксис хуже читать. Лучше использовать методы списка .append() и .insert():Срез аналоги .append() и insert()
my_list = [1, 2, 3, 4, 5] my_list[5:] = [6] # вставляем в конец — лучше использовать .append(6) print(my_list) # [1, 2, 3, 4, 5, 6] my_list[0:0] = [0] # вставляем в начало — лучше использовать .insert(0, 0) print(my_list) # [0, 1, 2, 3, 4, 5, 6] my_list[3:3] = [25] # вставляем между элементами — лучше использовать .insert(3, 25) print(my_list) # [0, 1, 2, 25, 3, 4, 5, 6]
- Можно менять части последовательности — это применение выглядит наиболее интересным, так как решает задачу просто и наглядно.
my_list = [1, 2, 3, 4, 5] my_list[1:3] = [20, 30] print(my_list) # [1, 20, 30, 4, 5] my_list[1:3] = [0] # нет проблем заменить два элемента на один print(my_list) # [1, 0, 4, 5] my_list[2:] = [40, 50, 60] # или два элемента на три print(my_list) # [1, 0, 40, 50, 60]
- Можно просто удалить часть последовательности
my_list = [1, 2, 3, 4, 5] my_list[:2] = [] # или del my_list[:2] print(my_list) # [3, 4, 5]
2.4 Выход за границы индекса
Обращение по индексу по сути является частным случаем среза, когда мы обращаемся только к одному элементу, а не диапазону. Но есть очень важное отличие в обработке ситуации с отсутствующим элементом с искомым индексом.
Обращение к несуществующему индексу коллекции вызывает ошибку:
my_list = [1, 2, 3, 4, 5]
print(my_list[-10]) # IndexError: list index out of range
print(my_list[10]) # IndexError: list index out of range
А в случае выхода границ среза за границы коллекции никакой ошибки не происходит:
my_list = [1, 2, 3, 4, 5]
print(my_list[0:10]) # [1, 2, 3, 4, 5] — отработали в пределах коллекции
print(my_list[10:100]) # [] - таких элементов нет — вернули пустую коллекцию
print(my_list[10:11]) # [] - проверяем 1 отсутствующий элемент - пустая коллекция, без ошибки
Примечание: Для тех случаев, когда функционала срезов недостаточно и требуются более сложные выборки, можно воспользоваться синтаксисом выражений-генераторов, рассмотрению которых посвещена 4 статья цикла.
3 Сортировка элементов коллекции
Сортировка элементов коллекции важная и востребованная функция, постоянно встречающаяся в обычных задачах. Тут есть несколько особенностей, на которых не всегда заостряется внимание, но которые очень важны.
3.1 Функция sorted()
Мы может использовать функцию sorted() для вывода списка сортированных элементов любой коллекции для последующее обработки или вывода.
- функция не меняет исходную коллекцию, а возвращает новый список из ее элементов;
- не зависимо от типа исходной коллекции, вернётся список (list) ее элементов;
- поскольку она не меняет исходную коллекцию, ее можно применять к неизменяемым коллекциям;
- Поскольку при сортировке возвращаемых элементов нам не важно, был ли у элемента некий индекс в исходной коллекции, можно применять к неиндексированным коллекциям;
- Имеет дополнительные не обязательные аргументы:
reverse=True — сортировка в обратном порядке
key=funcname (начиная с Python 2.4) — сортировка с помощью специальной функции funcname, она может быть как стандартной функцией Python, так и специально написанной вами для данной задачи функцией и лямбдой.
my_list = [2, 5, 1, 7, 3]
my_list_sorted = sorted(my_list)
print(my_list_sorted) # [1, 2, 3, 5, 7]
my_set = {2, 5, 1, 7, 3}
my_set_sorted = sorted(my_set, reverse=True)
print(my_set_sorted) # [7, 5, 3, 2, 1]
Пример сортировки списка строк по длине len() каждого элемента:
my_files = ['somecat.jpg', 'pc.png', 'apple.bmp', 'mydog.gif']
my_files_sorted = sorted(my_files, key=len)
print(my_files_sorted) # ['pc.png', 'apple.bmp', 'mydog.gif', 'somecat.jpg']
3.2 Функция reversed()
Функция reversed() применяется для последовательностей и работает по другому:
- возвращает генератор списка, а не сам список;
- если нужно получить не генератор, а готовый список, результат можно обернуть в list() или же вместо reversed() воспользоваться срезом [: :-1];
- она не сортирует элементы, а возвращает их в обратном порядке, то есть читает с конца списка;
- из предыдущего пункта понятно, что если у нас коллекция неиндексированная — мы не можем вывести её элементы в обратном порядке и эта функция к таким коллекциям не применима — получим «TypeError: argument to reversed() must be a sequence»;
- не позволяет использовать дополнительные аргументы — будет ошибка «TypeError: reversed() does not take keyword arguments».
my_list = [2, 5, 1, 7, 3]
my_list_sorted = reversed(my_list)
print(my_list_sorted) # <listreverseiterator object at 0x7f8982121450>
print(list(my_list_sorted)) # [3, 7, 1, 5, 2]
print(my_list[::-1]) # [3, 7, 1, 5, 2] - тот же результат с помощью среза
3.3 Методы списка .sort() и .reverse()
У списка (и только у него) есть особые методы .sort() и .reverse() которые делают тоже самое, что соответствующие функции sorted() и reversed(), но при этом:
- Меняют сам исходный список, а не генерируют новый;
- Возвращают None, а не новый список;
- поддерживают те же дополнительные аргументы;
- в них не надо передавать сам список первым параметром, более того, если это сделать — будет ошибка — не верное количество аргументов.
my_list = [2, 5, 1, 7, 3]
my_list.sort()
print(my_list) # [1, 2, 3, 5, 7]
Обратите внимание: Частая ошибка начинающих, которая не является ошибкой для интерпретатора, но приводит не к тому результату, который хотят получить.
my_list = [2, 5, 1, 7, 3]
my_list = my_list.sort()
print(my_list) # None
3.4 Особенности сортировки словаря
В сортировке словаря есть свои особенности, вызванные тем, что элемент словаря — это пара ключ: значение.
UPD: Так же, не забываем, что говоря о сортировке словаря, мы имеем ввиду сортировку полученных из словаря данных для вывода или сохранения в индексированную коллекцию. Сохранить данные сортированными в самом стандартном словаре не получится, они в нем, как и других неиндексированных коллекциях находятся в произвольном порядке.
- sorted(my_dict) — когда мы передаем в функцию сортировки словарь без вызова его дополнительных методов — идёт перебор только ключей, сортированный список ключей нам и возвращается;
- sorted(my_dict.keys()) — тот же результат, что в предыдущем примере, но прописанный более явно;
- sorted(my_dict.items()) — возвращается сортированный список кортежей (ключ, значение), сортированных по ключу;
- sorted(my_dict.values()) — возвращается сортированный список значений
my_dict = {'a': 1, 'c': 3, 'e': 5, 'f': 6, 'b': 2, 'd': 4}
mysorted = sorted(my_dict)
print(mysorted) # ['a', 'b', 'c', 'd', 'e', 'f']
mysorted = sorted(my_dict.items())
print(mysorted) # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6)]
mysorted = sorted(my_dict.values())
print(mysorted) # [1, 2, 3, 4, 5, 6]
Отдельные сложности может вызвать сортировка словаря не по ключам, а по значениям, если нам не просто нужен список значений, и именно выводить пары в порядке сортировки по значению.
Для решения этой задачи можно в качестве специальной функции сортировки передавать lambda-функцию lambda x: x[1] которая из получаемых на каждом этапе кортежей (ключ, значение) будет брать для сортировки второй элемент кортежа.
population = {"Shanghai": 24256800, "Karachi": 23500000, "Beijing": 21516000, "Delhi": 16787941}
# отсортируем по возрастанию населения:
population_sorted = sorted(population.items(), key=lambda x: x[1])
print(population_sorted)
# [('Delhi', 16787941), ('Beijing', 21516000), ('Karachi', 23500000), ('Shanghai', 24256800)]
UPD от ShashkovS: 3.5 Дополнительная информация по использованию параметра key при сортировке
Допустим, у нас есть список кортежей названий деталей и их стоимостей.
Нам нужно отсортировать его сначала по названию деталей, а одинаковые детали по убыванию цены.
shop = [('каретка', 1200), ('шатун', 1000), ('седло', 300),
('педаль', 100), ('седло', 1500), ('рама', 12000),
('обод', 2000), ('шатун', 200), ('седло', 2700)]
def prepare_item(item):
return (item[0], -item[1])
shop.sort(key=prepare_item)
Результат сортировки
for det, price in shop:
print('{:<10} цена: {:>5}р.'.format(det, price))
# каретка цена: 1200р.
# обод цена: 2000р.
# педаль цена: 100р.
# рама цена: 12000р.
# седло цена: 2700р.
# седло цена: 1500р.
# седло цена: 300р.
# шатун цена: 1000р.
# шатун цена: 200р.
Перед тем, как сравнивать два элемента списка к ним применялась функция prepare_item, которая меняла знак у стоимости (функция применяется ровно по одному разу к каждому элементу. В результате при одинаковом первом значении сортировка по второму происходила в обратном порядке.
Чтобы не плодить утилитарные функции, вместо использования сторонней функции, того же эффекта можно добиться с использованием лямбда-функции.
# Данные скопировать из примера выше
shop.sort(key=lambda x: (x[0], -x[1]))
Дополнительные детали и примеры использования параметра key:
UPD от ShashkovS: 3.6 Устойчивость сортировки
Допустим данные нужно отсортировать сначала по столбцу А по возрастанию, затем по столбцу B по убыванию, и наконец по столбцу C снова по возрастанию.
Если данные в столбце B числовые, то при помощи подходящей функции в key можно поменять знак у элементов B, что приведёт к необходимому результату.
А если все данные текстовые? Тут есть такая возможность.
Дело в том, что сортировка sort в Python устойчивая (начиная с Python 2.2), то есть она не меняет порядок «одинаковых» элементов.
Поэтому можно просто отсортировать три раза по разным ключам:
data.sort(key=lambda x: x['C'])
data.sort(key=lambda x: x['B'], reverse=True)
data.sort(key=lambda x: x['А'])
Дополнительная информация по устойчивости сортировки и примеры: wiki.python.org/moin/HowTo/Sorting#Sort_Stability_and_Complex_Sorts (на наглийском).
Приглашаю к обсуждению:
- Если я где-то допустил неточность или не учёл что-то важное — пишите в комментариях, важные комментарии будут позже добавлены в статью с указанием вашего авторства.
- Если какие-то моменты не понятны и требуется уточнение — пишите ваши вопросы в комментариях — или я или другие читатели дадут ответ, а дельные вопросы с ответами будут позже добавлены в статью.
Индексы и срезы в Python
Строки и списки в Python состоят из элементов, занимающих свои нумерованные позиции в иерархии. К любому элементу, можно обратиться по его порядковому номеру — индексу. Отсчет начинается с нуля и ведется слева направо.
Индекс строки в Python
Строка представляет собой упорядоченный набор символов. Это значит, что каждый символ в строке занимает свое место — индекс. Например, у строки ‘string’, символ ‘s’ имеет индекс 0 и далее по порядку:
- s — 0
- t — 1
- r — 2
- i — 3
- n — 4
- g — 5
Первый по счету символ в строке всегда будет иметь индекс 0. Таким образом, обратившись по индексу к элементу, мы можем узнать его значение. В чем и состоит смысл индексов. У пробела, так же есть индекс.
Так мы получим всю строку целиком:
get_str = 'это строка'
print(get_str)
это строка
А здесь, обратившись по индексу 5, получаем его значение — символ ‘t’.
get_s = 'это строка'
print(get_s[5])
t
При обращении к несуществующему индексу, программа выведет ошибку.
get_s = 'это строка'
print(get_s[10])
IndexError: string index out of range
Отрицательный индекс
Мы знаем точно, что у первого символа строки всегда будет индекс 0. А как насчет последнего символа? Ведь длина строки не всегда заранее известна. Для закрепления постоянного индекса для последнего символа, Python вводит понятие отрицательного индекса и предлагает вести отсчет наоборот, справа налево.
P y t h o n
-6 -5 -4 -3 -2 -1
get_last = 'Python'
print(get_last[-1])
n
Срез строки в Python
Иногда требуется получить из строки не один символ, а сразу несколько по некоторой закономерности — первые 2, каждый 3-ий или 4 последних. Для этого существуют срезы. Мы выборочно срезаем нужные символы и обращаемся по срезу. Надо отметить, что физически срезанные символы, остаются на своих местах. Сама строка никоим образом не меняется, мы работаем со срезанными копиями.
Возьмем первые три символа у строки ‘срезы Python’. В параметрах передадим два индекса — начало и конец среза. При срезе первый индекс входит включительно, а второй индекс не входит в выборку.
slice = 'срезы Python'
print(slice[0:3])
сре #символ 'з' не попал в выборку
Если не указаны начало или конец среза, то по умолчанию берётся первый или последний элемент коллекции.
slice = 'срезы Python'
print(slice[6:])
Python #с индекса 6 и до концаslice = 'срезы Python'
print(slice[:5])
срезы #с начала строки до 5-го индекса включительно
slice = 'срезы Python'
print(slice[:])
срезы Python #выводит строку целиком
Третьим параметром у срезов, может передаваться шаг.
slice = 'срезы Python'
print(slice[::2])
сеыPto #выводит символы через один
Индекс списка в Python
Список — это упорядоченная коллекция нумерованных элементов, где первый элемент начинается с нулевой позиции. Когда мы обратимся к 4-ому элементу, то получим 12.
a = [2, 3, 5, 9, 12, 16]
print(a[4])
12
Правила для индексов у списка, похожие для индексов у строк:
- обращение к несуществующему элементу, выведет ошибку
- первый индекс равен 0, а последний индекс -1
Заменить элемент в списке
Существует принципиальная разница — элементы в списках в отличие от элементов в строках можно заменять, удалять или добавлять. Мы обращаемся по индексу в 3-му элементу в списке d и присваиваем индексу новое значение. В результате произошла замена — 7 поменялась на 10.
d = [1, 3, 5, 7, 8]
d[3] = 10
print(d)
[1, 3, 5, 10, 8]
Удалить элемент из списка
Элемент со значением 15 под индексом 2, вылетел из списка.
f = [11, 13, 15, 17]
del f[2]
print(f)
[11, 13, 17]
Срез списка в Python
Со срезами у списков дело обстоит точно так же, как и у строк. Делаем выборку со 2-го индекса по 4-ый, не включая сам 4-ый индекс.
b = [21, 32, 54, 90, 22, 46]
print(b[2:4])
[54, 90]
Вывод четных элементов списка
Выведем все четные элементы списка, используя срезы. Первым параметром передаем 1-ый индекс, во втором параметре пишем двоеточие (по умолчанию выведется последний элемент списка) и третьим параметром указываем шаг для выводимых элементов.
c = [21, 22, 23, 24, 25, 26, 27]
print(c[1::2])
[22, 24, 26]
Итоги
Ранее мы научились создавать строку, узнали, какие у строк есть методы. Сегодня вы научились по индексам и срезам находить значения. Но на этом, познания о строках не заканчиваются и все самое интересное, вас ждет впереди.
- Создано 08.11.2019 10:03:33
- Михаил Русаков
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Python 3 #10: списки — срезы и методы: append, insert, pop, sort, index, count, reverse, clear
Для списков применим механизм срезов, о котором мы уже говорили, рассматривая строки. Например, пусть у нас имеется список из городов:
lst = ["Москва", "Санкт-Петербург", "Тверь", "Казань"]
Используя синтаксис:
список[start:end]
можно выделять элементы, начиная с индекса start и заканчивая, но не включая индекс end. В частности, вот такая конструкция:
возвратит список из двух городов:
<p align=center>['Санкт-Петербург', 'Тверь']
То есть, здесь создается новый объект list, содержащий эти элементы:
Прежний список lst не меняется. Если индексы принимают отрицательные значение, то отсчет идет с конца списка:
получим
[‘Тверь’]
так как индекс -1 – последний элемент не включается, остается только «Тверь». Или, можно записать так:
тогда возьмем с первого элемента и до предпоследнего:
[‘Москва’, ‘Санкт-Петербург’, ‘Тверь’]
У срезов можно записывать любые числовые индексы к ошибкам это не приведет. Например:
вернет список со 2-го элемента и по последний:
[‘Санкт-Петербург’, ‘Тверь’, ‘Казань’]
Этот же результат можно получить и так:
то есть, не указывая последний индекс, берутся все оставшиеся элементы. Если же записать срез так:
то элементы выбираются с самого начала и до третьего индекса, то есть, получим:
[‘Москва’, ‘Санкт-Петербург’, ‘Тверь’]
Если не указывать ни начало, ни конец, то будет возвращен список:
Спрашивается: создает ли данная операция копию списка? Да, создается и в этом легко убедиться, записав такие строчки:
c = lst[:] print(id(c), id(lst))
И мы увидим разные значения id, которые говорят, что обе переменные ссылаются на разные списки. Также копию списка, можно сделать с помощью функции-конструктора list:
Далее, в срезах можно указывать шаг следования (по умолчанию он равен 1). Для этого пишется еще одно двоеточие и указывается шаг:
получим:
[‘Москва’, ‘Тверь’]
Или, такие варианты:
lst[1:4:2] lst[:4:3] lst[1::2]
Если указать отрицательный шаг, то перебор будет происходить в обратном порядке:
Так как список – это изменяемый объект, то мы можем срезам присваивать новые значения. Делается это таким образом:
lst[1:3] = "Владимир", "Астрахань"
В результате, получаем список:
[‘Москва’, ‘Владимир’, ‘Астрахань’, ‘Казань’]
Или даже так. Большему срезу присвоить меньшее число элементов:
lst[0:3] = 'Пермь', 'Пенза'
В итоге получаем список:
[‘Пермь’, ‘Пенза’, ‘Казань’]
Однако, если нам нужно просто удалить какой-либо элемент, то это делается с помощью оператора del:
В результате будет удален элемент с индексом 1 из списка lst:
[‘Пермь’, ‘Казань’]
Методы списков
Давайте теперь предположим, что у нас имеется список из чисел:
a = [1, -54, 3, 23, 43, -45, 0]
и мы хотим в конец этого списка добавить значение. Это можно сделать с помощью метода:
И обратите внимание: метод append ничего не возвращает, то есть, он меняет сам список благодаря тому, что он относится к изменяемому типу данных. Поэтому писать здесь конструкцию типа
категорически не следует, так мы только потеряем весь наш список! И этим методы списков отличаются от методов строк, когда мы записывали:
string="Hello" string = string.upper()
Здесь метод upper возвращает измененную строку, поэтому все работает как и ожидается. А метод append ничего не возвращает, и присваивать значение None переменной a не имеет смысла, тем более, что все работает и так:
a = [1, -54, 3, 23, 43, -45, 0] a.append(100)
Причем, мы в методе append можем записать не только число, но и другой тип данных, например, строку:
тогда в конец списка будет добавлен этот элемент. Или, булевое значение:
Или еще один список:
И так далее. Главное, чтобы было указано одно конкретное значение. Вот так работать не будет:
Если нам нужно вставить элемент в произвольную позицию, то используется метод
Здесь мы указываем индекс вставляемого элемента и далее значение самого элемента.
Следующий метод remove удаляет элемент по значению:
a.remove(True) a.remove('hello')
Он находит первый подходящий элемент и удаляет его, остальные не трогает. Если же указывается несуществующий элемент:
то возникает ошибка. Еще один метод для удаления
выполняет удаление последнего элемента и при этом, возвращает его значение. В самом списке последний элемент пропадает. То есть, с помощью этого метода можно сохранять удаленный элемент в какой-либо переменной:
Также в этом методе можно указывать индекс удаляемого элемента, например:
Если нам нужно очистить весь список – удалить все элементы, то можно воспользоваться методом:
Получим пустой список. Следующий метод
a = [1, -54, 3, 23, 43, -45, 0] c = a.copy()
возвращает копию списка. Это эквивалентно конструкции:
В этом можно убедиться так:
и список c будет отличаться от списка a.
Следующий метод count позволяет найти число элементов с указанным значением:
Если же нам нужен индекс определенного значения, то для этого используется метод index:
возвратит 0, т.к. берется индекс только первого найденного элемента. Но, мы здесь можем указать стартовое значение для поиска:
Здесь поиск будет начинаться с индекса 1, то есть, со второго элемента. Или, так:
Ищем число 23 с 1-го индекса и по 5-й не включая его. Если элемент не находится
то метод приводит к ошибке. Чтобы этого избежать в своих программах, можно вначале проверить: существует ли такой элемент в нашем срезе:
и при значении True далее уже определять индекс этого элемента.
Следующий метод
меняет порядок следования элементов на обратный.
Последний метод, который мы рассмотрим, это
выполняет сортировку элементов списка по возрастанию. Для сортировки по убыванию, следует этот метод записать так:
Причем, этот метод работает и со строками:
lst = ["Москва", "Санкт-Петербург", "Тверь", "Казань"] lst.sort()
Здесь используется лексикографическое сравнение, о котором мы говорили, когда рассматривали строки.
Это все основные методы списков и чтобы вам было проще ориентироваться, приведу следующую таблицу:
Метод |
Описание |
append() |
Добавляет элемент в конец списка |
insert() |
Вставляет элемент в указанное место списка |
remove() |
Удаляет элемент по значению |
pop() |
Удаляет последний элемент, либо элемент с указанным индексом |
clear() |
Очищает список (удаляет все элементы) |
copy() |
Возвращает копию списка |
count() |
Возвращает число элементов с указанным значением |
index() |
Возвращает индекс первого найденного элемента |
reverse() |
Меняет порядок следования элементов на обратный |
sort() |
Сортирует элементы списка |
Задания для самоподготовки
1. Пользователь вводит с клавиатуры числа, до тех пор, пока не введет число 0. На основе введенных данных нужно сформировать список, состоящий из квадратов введенных чисел.
2. Написать программу удаления из списка
[‘+7912123456’, ‘+7915213456’, ‘+6915213456’, ‘+4915213456’, ‘+7915213456’]
всех номеров с кодом «+7».
3. Написать программу циклического сдвига элементов списка влево. Например, дан список:
[1,2,3,4,5,6]
после сдвига на один элемент влево, должны получить:
[2,3,4,5,6,1]
Реализовать через цикл, перебирая все элементы.
4. Написать аналогичную программу циклического сдвига, но теперь вправо.
Индексация строк | Python
Доступ к символам в строках основан на операции индексирования – после строки или имени переменной, ссылающейся на строку, в квадратных скобках указываются номера позиций необходимых символов.
Так же следует понимать, что этот самый доступ, основан на смещении, т.е. расстоянии символов от левого или правого края строки. Данное расстояние измеряется целыми числами и по сути определяет номер позиции символов в строке – их индекс. Подвох заключается в словосочетании «измеряется целыми числами«, а это означает, что индекс может быть как положительным так и отрицательным: положительные индексы – это отсчет от левого края, а отрицательные – от правого. Причем отсчет символов от левого края начинается с \(0\), а с правого начинается с \(-1\) (минус единицы).
В самом простом случае можно извлеч один произвольный символ:
>>> 'string'[0]
's'
>>>
>>> 'string'[5]
'g'
>>>
>>>
>>> s = 'STRING'
>>>
>>> s[0]
'S'
>>>
>>> s[5]
'G'
Так же мы можем извлеч срез – последовательность символов внутри исходной строки, которую еще иногда называют подстрокой:
>>> s = 'AAA***BBB^^^'
>>>
>>> s[0:3]
'AAA'
>>>
>>> s[3:6]
'***'
>>>
>>> s[9:12]
'^^^'
А еще мы можем извлекать символы из строки или среза с указанным шагом:
>>> s = 'a0-b1-c2-d3-e4-f5-g6'
>>>
>>> s[::3]
'abcdefg'
>>>
>>> s[1::3]
'0123456'
>>>
>>> s[2::3]
'------'
>>>
>>>
>>> s[3:12:3]
'bcd'
>>> s[9:1:-3]
'dcb'
Как видите, с одной стороны – все вроде бы просто, но с другой – особенно глядя на последние примеры, становится понятно, что какие-то сложности все-таки есть. Давайте разберемся по порядку.
Извлечение символов — S[i]
Извлечение одного символа из строки – это, действительно, самый простой случай. Давайте снова рассмотрим строку:
>>> s = 'STRING'
Что бы извлеч символы ‘S
‘, ‘R
‘ и ‘G
‘ мы можем выполнить следующие простые операции:
>>> s[0], s[2], s[5]
('S', 'R', 'G')
Но так как мы уже знаем, что индексы могут быть отрицательными, т.е. отсчитываться от конца строки, то для извлечения тех же символов мы можем выполнить и такие операции:
>>> s[-6], s[-4], s[-1]
('S', 'R', 'G')
Отрицательные и положительные индексы символов могут быть выражены через длину строки:
>>> s[4], s[-2]
('N', 'N')
>>>
>>> s[len(s) - 2], s[4 - len(s)]
('N', 'N')
Визуально отображение индексов на символы строки выглядит вот так:
Если указать индекс, который выходит за пределы строки, то это приведет к ошибке:
>>> s[10], s[-10]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Отсутствие индекса, так же считается ошибкой.
Извлечение срезов — S[i:j]
Извлечение срезов строк выполняется по двум индексам, которые разделяются двоеточием:
>>> s = '*a*bb*ccc*dddd*'
>>>
>>> s[1:2]
'a'
>>>
>>> s[3:5]
'bb'
>>>
>>> s[6:9]
'ccc'
>>>
>>> s[10:14]
'dddd'
Обратите внимание на то, что срез начинается с символа, индекс которого указан первым, а заканчивается перед символом, индекс которого указан вторым:
Тех же результатов можно добиться если указывать отрицательные индексы:
>>> s[-14:-13], s[-12:-10], s[-9:-6], s[-5:-1]
('a', 'bb', 'ccc', 'dddd')
Во всех предыдущих примерах первый индекс всегда был меньше второго, но если вдруг окажется наоборот, то это не приведет к ошибке, а возвратит пустую строку:
>>> s[5:1]
''
>>> s[-10:-14]
''
И даже, если индексы окажутся равны, мы все равно увидим пустую строку вместо сообщения об ошибке:
>>> s[1:1]
''
>>> s[-14:-14]
''
Появится ли сообщение об ошибке если не указать индексы вообще? Нет, вместо этого мы увидим всю строку целиком:
>>> s[:]
'*a*bb*ccc*dddd*'
Такое поведение связано с тем, что индексы начала и конца среза имеют значения по умолчанию: начало – всегда \(0\), конец – всегда len(s)
. Так что команда s[:]
является эквивалентной команде s[0:len(s)]
. Наличие таких предустановленных значений является весьма удобным, если мы хотим извлекать срезы от начала строки до указанного символа, или от некоторого символа до конца строки:
>>> s = '*a*bb*ccc*dddd*'
>>>
>>> s[:2] # эквивалентно s[:-13]
'*a'
>>>
>>> s[:5] # эквивалентно s[:-10]
'*a*bb'
>>>
>>> s[:-1] # эквивалентно s[:14]
'*a*bb*ccc*dddd'
>>>
>>> s[-3:] # эквивалентно s[12:]
'dd*'
>>>
>>> s[-10:] # эквивалентно s[5:]
'*ccc*dddd*'
Снова, обратите внимание на то, что если срез извлекается от начала строки до указанного символа, то сам указанный символ в разрез не включается. А если срез извлекается от указанного символа до конца строки, то этот символ будет включен в начало среза. Такое поведение гарантирует что конкатенация двух таких срезов будет равна исходной строке:
>>> s = 'xxxxYYYY'
>>>
>>> s[:4] + s[4:]
'xxxxYYYY'
>>>
>>> s[:-3] + s[-3:]
'xxxxYYYY'
Операция извлечения среза допускает указание индексов, выходящих за пределы строки:
>>> s = '*a*bb*ccc*dddd*'
>>>
>>> s[:100]
'*a*bb*ccc*dddd*'
>>>
>>> s[6:100]
'ccc*dddd*'
>>>
>>> s[100:]
''
Извлечение срезов с заданным шагом — S[i:j:k]
Что бы извлечь символы из среза с заданным шагом (их еще называют разреженные срезы), необходимо указать значение шага через двоеточие после операции извлечения среза:
>>> s = 'A1-B2-C3-D4-E5-'
>>>
>>> s[3:12:3]
'BCD'
>>>
>>> s[:9:2]
'A-2C-'
>>>
>>> s[3::4]
'B3-'
>>>
>>> s[::6]
'ACE'
Очевидно, что тех же результатов мы добьемся если не будем менять значения шага, а значения индексов начала и конца среза поменяем на отрицательные:
>>> s[-12:-3:3], s[:-6:2], s[-12::4]
('BCD', 'A-2C-', 'B3-')
Визуально все это можно представить вот так:
В возвращаемой строке оказываются только те символы исходной строки, которые обозначены оранжевым цветом. Символы, обозначенные зеленым цветом, входят в состав указанного среза, но не соответствуют значению шага, поэтому мы и не видим их в результирующей строке.
Величина шага имеет значение по умолчанию, равное \(1\) – это соответствует извлечению всех элементов подряд. А учитывая, что начало среза и его конец так же имеют установленные по умолчанию значения, равные \(0\) и len(s)
, то мы можем вообще ничего не указывать (кроме двух двоеточий, разумеется):
>>> s = 'A1-B2-C3-D4-E5-'
>>>
>>> s[::]
'A1-B2-C3-D4-E5-'
Может ли значение шага быть отрицательным? Да:
>>> 'ABCDEFG'[::-1]
'GFEDCBA'
>>>
>>> 'ABCDEFG'[::-2]
'GECA'
По сути, знак указанного числа в шаге указывает направление в котором выполняется извлечение символов из среза. Значение \(-1\) означает, что нужно извлеч каждый последующий символ, двигаясь от правого края к левому. А значение \(-2\) — извлеч каждый второй символ, так же двигаясь от конца к началу строки.
Давайте выполним несколько примеров и посмотрим, как это можно наглядно представить:
>>> s = 'ABCDEFGHIJKLMNO'
>>>
>>> s[::2]
'ACEGIKMO'
>>>
>>> s[::-2]
'OMKIGECA'
>>>
>>> s[::4]
'AEIM'
>>>
>>> s[::-4]
'OKGC'
Помните, мы говорили о том, что индекс начала среза должен быть меньше чем индекс его конца? На самом деле такая необходимость связана с направлением в котором извлекаются символы среза. По умолчанию, значение шага равняется \(1\) — это соответствует изъятию каждого символа в направлении от начала строки до ее конца. Именно поэтому мы ранее получали пустую строку, когда указывали левый индекс больше чем правый:
>>> s = 'ABCDEFGHIJKLMNO'
>>>
>>> s[10:4] # по умолчанию шаг равен 1
''
Глядя на пустую строку, котору вернул интерпретатор и картинку становится понятно, что что-то не так. Мы ясно видим, что извлечение начинается с индекса под номером \(10\), т.е. с символа «K
» и даже несмотря на то, что извлечение происходит слева направо (так как по умолчанию шаг равен \(1\)), символ «K
» просто обязан попасть в результирующую строку. Но его там нет!!!
Настало время осознать, что индексы символов в строке и их смещения – это не одно и то же. Работая с последовательностями нам проще всего воспринимать индексы символов (номера их позиций) чем их смещений. Я даже уверен что после того как вы разберетесь со смещениями, вы все равно будете представлять себе индексы.
Индексы и смещения символов
Что ж давайте сделаем небольшое отступление и попробуем разобраться. Вот уже знакомая нам строка:
>>> s = 'STRING'
А вот так мы отображаем индексы на символы:
Почему мы так делаем? Потому что это удобнее чем смещения:
Говоря о смещениях, мы подразумеваем левую границу символов (левую сторону квадратов в которых они изображены на рисунках). Так, например, смещение символа «S
» относительно левого края строки равно \(0\) т.е. он вообще не смещен, поэтому операция s[0]
его и возвращает. А смещение символа «G
» относительно правого края равно \(-1\), поэтому операция s[-1]
возвращает «G
«. На этом же принципе основаны и все другие операции индексирования, будь-то срезы или срезы с заданным шагом.
Даже поняв, что такое смещения символов, вы все равно будете опираться на их индексы. Глазами, указателем мыши, пальцем, вы все равно будете отсчитывать непосредственно сами символы, а не их левые границы. Просто потому, что это удобно. Просто потому, что в подавляющем большинстве это прекрасно работает и не вызывает никаких проблем.
Теперь, когда мы знаем, что такое смещения, нам гораздо проще понять почему операция s[4:2:1]
возвращает пустую строку вместо символа «I
«:
Глядя на эту картинку, нам начинает казаться, что символ «I
» с индексом \(4\) должен попасть в результирующую строку. Но интерпретатор Python ориентируется не по индексам, а смещениям и с его точки зрения все выглядит вот так:
Так как символ «I
» располагается перед смещением с номером \(4\), а отсчет ведется именно от смещений, то и в результирующей строке его быть не должно.
Понимание того, что строки индексируются именно по смещениям символов, проливает свет на многие нюансы. Например, взятие среза от некоторого символа до конца строки:
>>> s[2:6] # эквивалентно s[2:]
'RING'
Если посмотреть на эту операцию в контексте индексов, то можно утверждать, что мы указываем элемент с индексом \(6\), которого на самом деле не существует, но перед которым извлечение символов из строки должно остановиться.
Если же посмотреть на эту операцию в контексте смещений, то говорить о каких-то не существующих вещах уже не придется. Все эти смещения существуют и именно с ними работает интерпретатор Python.
Скорее всего, у вас возник вопрос по поводу того как работает операция s[::-1]
, ведь ее левый индекс по умолчанию равен \(0\), а правый – len(s)
, но даже не смотря на то, что извлечение символов должно выполняться справа налево, т.е. мы, по идее, должны увидеть пустую строку, мы видим, как все прекрасно работает:
>>> s = 'STRING'
>>>
>>> s[::-1]
'GNIRTS'
>>>
>>> s[::-2]
'GIT'
Такое исключение из правил, создано намеренно, а именно – для удобства. Потому что это, действительно, удобнее чем каждый раз писать, что-то вроде s[len(s):0:-1]
или s[len(s):0:-2]
.
Отрицательное значение шага
Если мы хотим извлекать элементы из срезов строк в обратном порядке, то и границы срезов так же необходимо указывать в обратном порядке:
>>> s = 'ABCDEFGHIJKLMNO'
>>>
>>> s[11:2:-2]
'LJHFD'
>>>
>>> s[:4:-3]
'OLIF'
>>>
>>> s[10::-4]
'KGC'
>>>
>>> s[-3:-6:-7]
'M'
Помните мы задавались вопросом о том, как работает операция s[::-1]
? И был дан расплывчато-туманный ответ, что это яко бы просто техническая особенность, созданная для удобства. Так вот это действительно технически реализованный трюк, который заключается в том, установленные по умолчанию значения начала и конца среза (начало – \(0\), конец – len(s)
) меняются местами, если величина шага имеет отрицательное значение:
>>> s[::2], s[0:len(s):2]
('ACEGIKMO', 'ACEGIKMO')
>>>
>>> s = 'ABCDEFGHIJKLMNO'
>>> s[::-2], s[-1:-len(s)-1:-2]
('OMKIGECA', 'OMKIGECA')
Возможно вы немного удивились, ожидая вместо команды s[-1:-len(s)-1:-2]
увидеть команду s[len(s):0:-2]
. Но если вспомнить, что символы извлекаются не по индексам, а по смещениям, так же вспомнив, что извлечение среза выполняется от первого указанного смещения до второго, то станет ясно, что команда s[len(s):0:-2]
выдаст не то, что нужно:
>>> s[len(s):0:-2], s[::-2], s[-1:-len(s)-1:-2]
('OMKIGEC', 'OMKIGECA', 'OMKIGECA')
В заключение, хочется напомнить о двух простых правилах из Дзена Python:
- Простое лучше чем сложное;
- Сложное лучше чем запутанное.
Почему именно эти правила. Потому что вам может захотеться использовать в своем коде какие-то, так сказать, хитро-выдуманные трюки с индексированием. С одной стороны: «Почему бы и нет??? Ведь программирование – это еще и способ самовыражения!». Но с другой стороны – это еще замечательный способ вынести мозг и себе, и что хуже всего, другим людям. Так что, если вдруг, вы придумаете, каой-нибудь фокус с индексированием строк, то не поленитесь раскрыть его секрет в комментариях к коду.
Сам по себе механизм индексирования устроен довольно просто. Тем не менее, даже из такой «простоты» можно слепить что-то вроде этого:
>>> sym = 'ABCDEFGHIJ'
>>> num = '1234567890'
>>> i = 2
>>>
>>> sym[int(num[i])-len(sym):int(num[len(sym)-i])-i:int(num[i])]
'DG'
Подобные фокусы имеют полное право на существование, но лучше их оставить для чемпионатов по программированию.
Строка фрагмента Python — JournalDev
Строка Python поддерживает нарезку для создания подстроки. Обратите внимание, что строка Python является неизменной, при нарезке из исходной строки создается новая подстрока, а исходная строка остается неизменной.
Строка фрагмента Python
Синтаксис строки фрагмента Python:
str_object [start_pos: end_pos: шаг]
Нарезка начинается с индекса start_pos (включен) и заканчивается индексом end_pos (исключая). Параметр step используется для указания шагов от начала до конца индекса.
Python Разделение строк всегда следует этому правилу: s [: i] + s [i:] == s для любого индекса «i».
Все эти параметры являются необязательными — значение по умолчанию start_pos равно 0, значение по умолчанию end_pos — длина строки, а значение шага по умолчанию — 1.
Давайте рассмотрим несколько простых примеров функции среза строки для создания подстроки.
s = 'HelloWorld'
печать (ы [:])
печать (s [::])
Выход:
Привет мир
Привет мир
Обратите внимание, что, поскольку ни один из параметров среза не был предоставлен, подстрока равна исходной строке.
Давайте рассмотрим еще несколько примеров разрезания строки.
s = 'HelloWorld'
first_five_chars = s [: 5]
печать (first_five_chars)
third_to_fifth_chars = s [2: 5]
печать (third_to_fifth_chars)
Выход:
Привет
LLO
Обратите внимание, что значение индекса начинается с 0, поэтому start_pos 2 относится к третьему символу в строке.
Перевернуть строку с помощью нарезки
Мы можем перевернуть строку с помощью нарезки, указав значение шага как -1.
s = 'HelloWorld'
reverse_str = s [:: - 1]
печать (reverse_str)
Вывод: dlroWolleH
Давайте рассмотрим некоторые другие примеры использования шагов и отрицательных значений индекса.
s1 = s [2: 8: 2]
печать (s1)
Вывод: loo
Здесь подстрока содержит символы из индексов 2,4 и 6.
s1 = s [8: 1: -1]
печать (s1)
Вывод: lroWoll
Здесь значения индекса берутся от конца до начала.Подстрока состоит из индексов с 1 по 7 от конца до начала.
s1 = s [8: 1: -2]
печать (s1)
Вывод: lool
Срез Python также работает с отрицательными индексами, в этом случае start_pos исключается, а end_pos включается в подстроку.
s1 = s [-4: -2]
печать (s1)
Вывод: или
Нарезка строки Python изящно обрабатывает индексы вне диапазона.
>>> s = 'Python'
>>> s [100:]
«»
>>> s [2:50]
«Тунце»
Это все, что касается функции фрагмента строки Python для создания подстроки.
Вы можете получить полный скрипт Python и другие примеры Python из нашего репозитория GitHub. ,Python String Slicing — Learn By Example
Чтобы получить доступ к диапазону символов в строке, вам необходимо разрезать строку. Один из способов сделать это — использовать простой оператор нарезки :
С помощью этого оператора вы можете указать, где начать нарезку, где закончить и указать шаг.
Нарезка строки
Если S — строка, выражение S [start: stop: step] возвращает часть строки от начала индекса до остановки индекса с шагом размера шага.
Синтаксис
Базовый пример
Вот базовый пример нарезки строк.
S = «ABCDEFGHI»
print (S [2: 7]) # CDEFG
Обратите внимание, что элемент с индексом 7 'H'
не включается.
Срез с отрицательными индексами
Вы также можете указать отрицательные индексы при разрезании строки.
S = «ABCDEFGHI»
print (S [-7: -2]) # CDEFG
Срез с положительными и отрицательными индексами
Вы можете указать как положительные, так и отрицательные индексы одновременно.
S = «ABCDEFGHI»
print (S [2: -5]) # CD
Укажите шаг нарезки
Вы можете указать шаг нарезки, используя параметр step. Параметр step является необязательным и по умолчанию равен 1.
# Возвращает каждый второй элемент между позициями 2–7.
S = 'ABCDEFGHI'
print (S [2: 7: 2]) # CEG
Отрицательный размер шага
Можно даже указать отрицательный размер шага.
# Возвращает каждый второй элемент с 6 по 1 в обратном порядке.
S = 'ABCDEFGHI'
print (S [6: 1: -2]) # GEC
Slice at Beginning & End
Если пропустить начальный индекс, слайс начинается с индекса 0.Это означает, что S [: stop]
эквивалентно S [0: stop]
# Вырезать первые три символа из строки
S = 'ABCDEFGHI'
print (S [: 3]) # ABC
Принимая во внимание, что отсутствие индекса остановки расширяет срез до конца строки. Это означает, что S [начало:]
эквивалентно S [начало: len (S)]
# Вырезать последние три символа из строки
S = 'ABCDEFGHI'
print (S [6:]) # GHI
Перевернуть строку
Вы можете перевернуть строку, пропустив оба индекса запуска и остановки и указав шаг как -1.
S = «ABCDEFGHI»
print (S [:: - 1]) # IHGFEDCBA
.Нарезка строки — Настоящий Python
На предыдущем уроке вы увидели, как можно получить доступ к отдельным символам в строке с помощью индексации. В этом уроке вы узнаете, как расширить синтаксис для извлечения подстрок из строки. Этот метод известен как нарезка строк. Вы попрактикуетесь в использовании стандартного синтаксиса и узнаете, как пропуск первого или последнего индекса расширяет срез. Вы также узнаете, как указать шаг в отрезке строки с помощью третьего индекса.
Вот несколько примеров нарезки строк:
>>> >>> s = 'mybacon'
>>> s [2: 5]
«БАК»
>>> s [2: 7]
'бекон'
>>> s [0: 2]
«Мой»
Вы можете опустить первый или последний индекс:
>>> >>> s = 'mybacon'
>>> s [: 2]
«Мой»
>>> s [: 5]
'Mybac'
>>> s [2:]
'бекон'
>>> s [2: len (s)]
>>> s [: 2] + s [2:]
'Mybacon'
>>> s [:]
'Mybacon'
>>> t = s [:]
>>> т
'Mybacon'
>>> id (s)
4380975712
>>> id (t)
4380975712
>>> s == t
Правда
>>> s is t
Правда
>>> s [2: 2]
«»
>>> s [4: 2]
«»
Вот минус в
.slice — расширенная нарезка строкой в python
Переполнение стека- Товары
- Клиенты
- Случаи использования
- Переполнение стека Общественные вопросы и ответы
- Команды Частные вопросы и ответы для вашей команды
- предприятие Частные вопросы и ответы для вашего предприятия
- работы Программирование и связанные с ним возможности технической карьеры
- Талант Нанять технических талантов
- реклама Обратитесь к разработчикам по всему миру