Понимание обозначения среза - PullRequest
2785 голосов
/ 04 февраля 2009

Мне нужно хорошее объяснение (ссылки плюс) на нотации Python.

Мне эта запись нуждается в небольшом подборе.

Выглядит очень мощно, но я не совсем понял, где это.

Ответы [ 31 ]

13 голосов
/ 26 мая 2016

Мой мозг, кажется, рад принять, что lst[start:end] содержит start -й элемент. Я мог бы даже сказать, что это «естественное предположение».

Но иногда возникает сомнение, и мой мозг просит заверить, что он не содержит end -ого элемента.

В эти моменты я полагаюсь на эту простую теорему:

for any n,    lst = lst[:n] + lst[n:]

Это симпатичное свойство говорит мне, что lst[start:end] не содержит end -й элемент, потому что он находится в lst[end:].

Обратите внимание, что эта теорема верна для любого n. Например, вы можете проверить, что

lst = range(10)
lst[:-42] + lst[-42:] == lst

возвращает True.

10 голосов
/ 04 сентября 2017

В Python самая основная форма для нарезки следующая:

l[start:end]

, где l - некоторая коллекция, start - включающий индекс, а end - исключительный.

In [1]: l = list(range(10))

In [2]: l[:5] # first five elements
Out[2]: [0, 1, 2, 3, 4]

In [3]: l[-5:] # last five elements
Out[3]: [5, 6, 7, 8, 9]

При нарезке с начала вы можете опустить нулевой индекс, а при срезании до конца вы можете опустить конечный индекс, поскольку он избыточен, поэтому не будьте многословны:

In [5]: l[:3] == l[0:3]
Out[5]: True

In [6]: l[7:] == l[7:len(l)]
Out[6]: True

Отрицательные целые числа полезны при выполнении смещений относительно конца коллекции:

In [7]: l[:-1] # include all elements but the last one
Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]

In [8]: l[-3:] # take the last 3 elements
Out[8]: [7, 8, 9]

Можно указывать индексы, выходящие за границы при нарезке, такие как:

In [9]: l[:20] # 20 is out of index bounds, l[20] will raise an IndexError exception
Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [11]: l[-20:] # -20 is out of index bounds, l[-20] will raise an IndexError exception
Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Имейте в виду, что результатом нарезки коллекции является совершенно новая коллекция. Кроме того, при использовании обозначения среза в назначениях длина назначения среза не обязательно должна быть одинаковой. Значения до и после назначенного среза будут сохранены, а коллекция будет уменьшаться или увеличиваться, чтобы содержать новые значения:

In [16]: l[2:6] = list('abc') # assigning less elements than the ones contained in the sliced collection l[2:6]

In [17]: l
Out[17]: [0, 1, 'a', 'b', 'c', 6, 7, 8, 9]

In [18]: l[2:5] = list('hello') # assigning more elements than the ones contained in the sliced collection l [2:5]

In [19]: l
Out[19]: [0, 1, 'h', 'e', 'l', 'l', 'o', 6, 7, 8, 9]

Если вы пропустите начальный и конечный индексы, вы создадите копию коллекции:

In [14]: l_copy = l[:]

In [15]: l == l_copy and l is not l_copy
Out[15]: True

Если начальный и конечный индексы опущены при выполнении операции присваивания, весь контент коллекции будет заменен копией того, на что есть ссылка:

In [20]: l[:] = list('hello...')

In [21]: l
Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']

Помимо базовой нарезки, также можно применять следующие обозначения:

l[start:end:step]

, где l - это коллекция, start - это инклюзивный индекс, end - это эксклюзивный индекс, а step - это шаг, который можно использовать, чтобы взять каждый элемент nth в l.

In [22]: l = list(range(10))

In [23]: l[::2] # take the elements which indexes are even
Out[23]: [0, 2, 4, 6, 8]

In [24]: l[1::2] # take the elements which indexes are odd
Out[24]: [1, 3, 5, 7, 9]

Использование step предоставляет полезную хитрость для обращения коллекции в Python:

In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Также можно использовать отрицательные целые числа для step в качестве следующего примера:

In[28]:  l[::-2]
Out[28]: [9, 7, 5, 3, 1]

Однако использование отрицательного значения для step может привести к путанице. Более того, чтобы быть Pythonic, вы должны избегать использования start, end и step в одном слайсе. В случае, если это требуется, попробуйте выполнить это в двух заданиях (одно для нарезки, а другое для продвижения).

In [29]: l = l[::2] # this step is for striding

In [30]: l
Out[30]: [0, 2, 4, 6, 8]

In [31]: l = l[1:-1] # this step is for slicing

In [32]: l
Out[32]: [2, 4, 6]
9 голосов
/ 07 октября 2017

Большинство из приведенных выше ответов проясняется относительно обозначения слайса. Синтаксис расширенного индексирования, используемый для нарезки: aList[start:stop:step] основные примеры

enter image description here

Дополнительные примеры нарезки: 15 расширенных срезов

8 голосов
/ 28 июля 2017

Ниже приведен пример индекса строки

 +---+---+---+---+---+
 | H | e | l | p | A |
 +---+---+---+---+---+
 0   1   2   3   4   5
-5  -4  -3  -2  -1

str="Name string"

Пример нарезки: [начало: конец: шаг]

str[start:end] # items start through end-1
str[start:]    # items start through the rest of the array
str[:end]      # items from the beginning through end-1
str[:]         # a copy of the whole array

Ниже приведен пример использования

print str[0]=N
print str[0:2]=Na
print str[0:7]=Name st
print str[0:7:2]=Nm t
print str[0:-1:2]=Nm ti
6 голосов
/ 04 апреля 2018

Я хочу добавить один пример Hello world, который объясняет основы слайсов для самых начинающих. Это мне очень помогло.

Давайте создадим список с шестью значениями ['P', 'Y', 'T', 'H', 'O', 'N']:

+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
  0   1   2   3   4   5 

Теперь простейшими срезами этого списка являются его подсписки. Обозначение [<index>:<index>], и ключ должен прочитать это как это:

[ start cutting before this index : end cutting before this index ]

Теперь, если вы сделаете фрагмент [2:5] из списка выше, это произойдет:

        |           |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
  0   1 | 2   3   4 | 5 

Вы сделали вырез перед элементом с индексом 2 и еще один вырез перед элементом с индексом 5 Таким образом, результатом будет срез между этими двумя разрезами, список ['T', 'H', 'O'].

6 голосов
/ 12 декабря 2017

По-моему, вы лучше поймете и запомните нотацию Python для разрезания строк, если посмотрите на нее следующим образом (читайте дальше).

Давайте поработаем со следующей строкой ...

azString = "abcdefghijklmnopqrstuvwxyz"

Для тех, кто не знает, вы можете создать любую подстроку из azString, используя обозначение azString[x:y]

Исходя из других языков программирования, именно тогда здравый смысл становится нарушенным. Что такое х и у?

Мне пришлось сесть и запустить несколько сценариев в своем поиске техники запоминания, которая поможет мне вспомнить, что такое x и y, и поможет мне правильно нарезать строки с первой попытки.

Мой вывод заключается в том, что x и y следует рассматривать как граничные индексы, которые окружают строки, которые мы хотим добавить. Таким образом, мы должны увидеть выражение как azString[index1, index2] или еще более ясно как azString[index_of_first_character, index_after_the_last_character].

Вот пример визуализации этого ...

Letters   a b c d e f g h i j ...
         ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 
Indexes  0 1 2 3 4 5 6 7 8 9 ... 
             |           |
cdefgh    index1       index2

Так что все, что вам нужно сделать, если установить для index1 и index2 значения, которые будут окружать желаемую подстроку. Например, чтобы получить подстроку «cdefgh», вы можете использовать azString[2:8], потому что индекс слева от «c» равен 2, а индекс справа от «h» равен 8.

Помните, что мы устанавливаем границы. И эти границы - это позиции, в которые вы можете поместить несколько скобок, которые будут обернуты вокруг подстроки, как это ...

a b [ c d e f g h ] i j

Этот трюк работает постоянно и его легко запомнить.

4 голосов
/ 19 декабря 2017

Если вы чувствуете, что отрицательные индексы в разрезании сбивают с толку, вот очень простой способ подумать об этом: просто замените отрицательный индекс на len - index. Так, например, замените -3 на len(list) - 3.

Лучший способ проиллюстрировать, что делает нарезка внутри, просто показать это в коде, который реализует эту операцию:

def slice(list, start = None, end = None, step = 1):
  # take care of missing start/end parameters
  start = 0 if start is None else start
  end = len(list) if end is None else end

  # take care of negative start/end parameters
  start = len(list) + start if start < 0 else start
  end = len(list) + end if end < 0 else end

  # now just execute for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]
3 голосов
/ 23 июля 2018

Основной метод нарезки - определение начальной точки, точки остановки и размера шага - также известный как шаг.

Сначала мы создадим список значений, которые мы будем использовать при нарезке.

Создайте два списка для нарезки, первый - это числовой список от 1 до 9 (Список A). Второй также числовой список, от 0 до 9 (список B)

A = list(range(1,10,1)) # start,stop,step
B = list(range(9))

print("This is List A:",A)
print("This is List B:",B)

Индексируйте число 3 из A и число 6 из B.

print(A[2])
print(B[6])

Базовая нарезка

Расширенный синтаксис индексации, используемый для нарезки, - это aList [start: stop: step]. Аргумент start и шаг по умолчанию равны none - единственным обязательным аргументом является stop. Вы заметили, что это похоже на то, как диапазон использовался для определения списков A и B? Это связано с тем, что объект слайса представляет собой набор индексов, заданных диапазоном (начало, остановка, шаг). Документация Python 3.4

Как видите, определение только stop возвращает один элемент. Поскольку в начале по умолчанию ничего нет, это приводит к извлечению только одного элемента.

Важно отметить, что первый элемент - это индекс 0, а не индекс 1. Именно поэтому мы используем 2 списка для этого упражнения. Элементы списка A нумеруются в соответствии с порядковым положением (первый элемент равен 1, второй элемент равен 2 и т. Д.), А элементы списка B представляют собой числа, которые будут использоваться для их индексации ([0] для первого элемента 0 и т. Д.). ).

С расширенным синтаксисом индексации мы получаем диапазон значений. Например, все значения извлекаются с помощью двоеточия.

A[:]

Чтобы извлечь подмножество элементов, необходимо определить начальную и конечную позиции.

Учитывая шаблон aList [start: stop], получить первые два элемента из списка A

1 голос
/ 28 декабря 2018

Легко понять, можно ли связать нарезку с range, что дает индексы. Мы можем разделить нарезки на следующие две категории:


1. Нет шага или шага> 0. Например, [i:j] или [i:j:k] (k> 0)

Предположим, что последовательность s=[1,2,3,4,5].

  • если 0<i<len(s) и 0<j<len(s), то [i:j:k] -> range(i,j,k)

Например, [0:3:2] -> range(0,3,2) -> 0, 2

  • если i>len(s) или j>len(s), то i=len(s) или j=len(s)

Например, [0:100:2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4

  • если i<0 или j<0, то i=max(0,len(s)+i) или j=max(0,len(s)+j)

Например, [0:-3:2] -> range(0,len(s)-3,2) -> range(0,2,2) -> 0

Для другого примера, [0:-1:2] -> range(0,len(s)-1,2) -> range(0,4,2) -> 0, 2

  • если i не указано, то i=0

Например, [:4:2] -> range(0,4,2) -> range(0,4,2) -> 0, 2

  • если j не указано, то j=len(s)

Например, [0::2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4


2. Шаг <0. Например, <code>[i:j:k] (k <0) </h2> Предположим, что последовательность s=[1,2,3,4,5]. если 0<i<len(s) и 0<j<len(s), то [i:j:k] -> range(i,j,k) Например, [5:0:-2] -> range(5,0,-2) -> 5, 3, 1 если i>len(s) или j>len(s), то i=len(s)-1 или j=len(s)-1 Например, [100:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2 если i<0 или j<0, то i=max(-1,len(s)+i) или j=max(-1,len(s)+j) Например, [-2:-10:-2] -> range(len(s)-2,-1,-2) -> range(3,-1,-2) -> 3, 1 если i не указано, то i=len(s)-1 Например, [:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2 если j не указано, то j=-1 Например, [2::-2] -> range(2,-1,-2) -> 2, 0 Для другого примера, [::-1] -> range(len(s)-1,-1,-1) -> range(4,-1,-1) -> 4, 3, 2, 1, 0 В итоге

enter image description here

0 голосов
/ 14 июня 2019

Я немного разочарован тем, что не могу найти онлайн-источник или документацию по Python, которая точно описывает, что делает нарезка.

Я принял предложение Аарона Холла и прочитал соответствующие части исходного кода CPython, затем написал некоторый код Python, который выполняет нарезку аналогично тому, как это делается в CPython. Я тестировал свой код в Python 3 на миллионах случайных тестов в целочисленных списках.

Вы можете найти полезные ссылки в моем коде на соответствующие функции в CPython.

# return the result of slicing list x
# See the part of list_subscript() in listobject.c that pertains
# to when the indexing item is a PySliceObject
def slicer(x, start=None, stop=None, step=None):
    # Handle slicing index values of None, and a step value of 0.
    # See PySlice_Unpack() in sliceobject.c, which
    # extracts start, stop, step from a PySliceObject.
    maxint = 10000000       # a hack to simulate PY_SSIZE_T_MAX
    if step == None:
        step = 1
    elif step == 0:
        raise ValueError('slice step cannot be zero')

    if start == None:
        start = maxint if step < 0 else 0
    if stop == None:
        stop = -maxint if step < 0 else maxint

    # Handle negative slice indexes and bad slice indexes.
    # Compute number of elements in the slice as slice_length.
    # See PySlice_AdjustIndices() in sliceobject.c
    length = len(x)
    slice_length = 0

    if start < 0:
        start += length
        if start < 0:
            start = -1 if step < 0 else 0
    elif start >= length:
        start = length - 1 if step < 0 else length

    if stop < 0:
        stop += length
        if stop < 0:
            stop = -1 if step < 0 else 0
    elif stop > length:
        stop = length - 1 if step < 0 else length

    if step < 0:
        if stop < start:
            slice_length = (start - stop - 1) // (-step) + 1
    else: 
        if start < stop:
            slice_length = (stop - start - 1) // step + 1

    # cases of step = 1 and step != 1 are treated separately
    if slice_length <= 0:
        return []
    elif step == 1:
        # see list_slice() in listobject.c
        result = []
        for i in range(stop - start):
            result.append(x[i+start])
        return result
    else:
        result = []
        cur = start
        for i in range(slice_length):
            result.append(x[cur])
            cur += step
        return result
...