Відповіді:
Це дуже просто:
a[start:stop] # items start through stop-1
a[start:] # items start through the rest of the array
a[:stop] # items from the beginning through stop-1
a[:] # a copy of the whole array
Також є step
значення, яке можна використовувати з будь-яким із перерахованих вище:
a[start:stop:step] # start through not past stop, by step
Ключовим моментом, який слід пам’ятати, є те, що :stop
значення представляє перше значення, яке не знаходиться у вибраному фрагменті. Отже, різниця між stop
і start
- кількістю обраних елементів (якщо step
дорівнює 1, за замовчуванням).
Інша особливість полягає в тому, що start
або stop
може бути від’ємне число, що означає, що воно рахується від кінця масиву замість початку. Тому:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
Так само step
може бути від’ємне число:
a[::-1] # all items in the array, reversed
a[1::-1] # the first two items, reversed
a[:-3:-1] # the last two items, reversed
a[-3::-1] # everything except the last two items, reversed
Python є доброзичливим до програміста, якщо є менше елементів, ніж ви просите. Наприклад, якщо ви запитуєте a[:-2]
і a
містить лише один елемент, ви отримуєте порожній список замість помилки. Іноді ви віддаєте перевагу помилку, тому ви повинні усвідомлювати, що це може статися.
slice()
об'єктаОператор нарізки []
фактично використовується в наведеному вище коді з slice()
об'єктом, використовуючи :
позначення (що діє лише в межах []
), тобто:
a[start:stop:step]
еквівалентно:
a[slice(start, stop, step)]
Об'єкти зрізів також поводяться дещо по-різному, залежно від кількості аргументів, аналогічно range()
, тобто обидва slice(stop)
і slice(start, stop[, step])
підтримуються. Щоб пропустити вказівку заданого аргументу, можна скористатися None
так, що, наприклад a[start:]
, еквівалентно a[slice(start, None)]
або a[::-1]
еквівалентно a[slice(None, None, -1)]
.
Хоча :
позначення на основі дуже корисні для простого нарізання, явне використання slice()
об'єктів спрощує програмну генерацію нарізки.
None
будь-який з порожніх пробілів. Наприклад, [None:None]
робить цілу копію. Це корисно, коли вам потрібно вказати кінець діапазону за допомогою змінної та потрібно включити останній елемент.
del
означає позначення wrt-фрагментів. Зокрема, del arr[:]
це не відразу очевидно ("arr [:] робить копію, тому дель видаляє цю копію ???" тощо)
Підручник з Python розповідає про це (прокрутіть трохи вниз, поки ви не перейдете до частини про нарізання).
Художня діаграма ASCII також корисна для запам'ятовування роботи зрізів:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Один із способів запам’ятати, як працюють фрагменти, - це думати про індекси як на вказівку між символами, лівий край першого символу пронумерований 0. Тоді правий край останнього символу рядка з n символів має індекс n .
a[-4,-6,-1]
це буде, yP
але воно є ty
. Що завжди працює - це мислити символами чи слотами та використовувати індексацію як напіввідкритий інтервал - справа-відкрито, якщо позитивний крок, ліво-відкрито, якщо негативний крок.
x[:0]
це робиться, коли починається з початку), тому вам доведеться робити невеликі масиви спеціального випадку. : /
Перерахування можливостей, дозволених граматикою:
>>> seq[:] # [seq[0], seq[1], ..., seq[-1] ]
>>> seq[low:] # [seq[low], seq[low+1], ..., seq[-1] ]
>>> seq[:high] # [seq[0], seq[1], ..., seq[high-1]]
>>> seq[low:high] # [seq[low], seq[low+1], ..., seq[high-1]]
>>> seq[::stride] # [seq[0], seq[stride], ..., seq[-1] ]
>>> seq[low::stride] # [seq[low], seq[low+stride], ..., seq[-1] ]
>>> seq[:high:stride] # [seq[0], seq[stride], ..., seq[high-1]]
>>> seq[low:high:stride] # [seq[low], seq[low+stride], ..., seq[high-1]]
Звичайно, якщо (high-low)%stride != 0
, то кінцева точка буде трохи нижчою, ніж high-1
.
Якщо stride
від’ємник, впорядкування дещо зміниться, оскільки ми підраховуємо:
>>> seq[::-stride] # [seq[-1], seq[-1-stride], ..., seq[0] ]
>>> seq[high::-stride] # [seq[high], seq[high-stride], ..., seq[0] ]
>>> seq[:low:-stride] # [seq[-1], seq[-1-stride], ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]
Розширене нарізання (комами та еліпсами) в основному використовується лише спеціальними структурами даних (наприклад, NumPy); основні послідовності не підтримують їх.
>>> class slicee:
... def __getitem__(self, item):
... return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
repr
__getitem__
є; ваш приклад еквівалентний apple[slice(4, -4, -1)]
.
Наведені вище відповіді не обговорюють призначення фрагментів. Щоб зрозуміти призначення фрагментів, корисно додати іншу концепцію до мистецтва ASCII:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
Slice position: 0 1 2 3 4 5 6
Index position: 0 1 2 3 4 5
>>> p = ['P','y','t','h','o','n']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
'P'
>>> p[5]
'n'
# Slicing gives lists
>>> p[0:1]
['P']
>>> p[0:2]
['P','y']
Одне евристичне, для відрізка від нуля до n подумайте: «нуль - це початок, почніть з початку і візьміть n елементів у списку».
>>> p[5] # the last of six items, indexed from zero
'n'
>>> p[0:5] # does NOT include the last item!
['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
['P','y','t','h','o','n']
Інша евристика - "для будь-якого фрагмента замініть початок на нуль, застосуйте попередній евристичний, щоб отримати кінець списку, а потім підрахуйте перше число назад, щоб відрізати елементи з початку"
>>> p[0:4] # Start at the beginning and count out 4 items
['P','y','t','h']
>>> p[1:4] # Take one item off the front
['y','t','h']
>>> p[2:4] # Take two items off the front
['t','h']
# etc.
Перше правило присвоєння фрагмента полягає в тому, що оскільки фрагмент повертає список, для призначення фрагмента потрібен список (або інший ітерабельний):
>>> p[2:3]
['t']
>>> p[2:3] = ['T']
>>> p
['P','y','T','h','o','n']
>>> p[2:3] = 't'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable
Друге правило присвоєння фрагментів, яке ви також можете бачити вище, полягає в тому, що будь-яка частина списку повертається шляхом індексації фрагментів, це та сама частина, яка змінюється присвоєнні фрагмента:
>>> p[2:4]
['T','h']
>>> p[2:4] = ['t','r']
>>> p
['P','y','t','r','o','n']
Третє правило присвоєння фрагментів - присвоєний список (ітерабельний) не повинен мати однакову довжину; індексований фрагмент просто вирізається і масово замінюється тим, що йому призначено:
>>> p = ['P','y','t','h','o','n'] # Start over
>>> p[2:4] = ['s','p','a','m']
>>> p
['P','y','s','p','a','m','o','n']
Найскладніша частина, до якої звикнути, - це присвоєння порожнім скибочкам. Використовуючи евристичні 1 і 2, можна просто обвести голову, вказуючи порожній фрагмент:
>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
['P','y','t','h']
>>> p[1:4]
['y','t','h']
>>> p[2:4]
['t','h']
>>> p[3:4]
['h']
>>> p[4:4]
[]
А потім, як тільки ви це побачили, присвоєння фрагменту порожньому фрагменту теж має сенс:
>>> p = ['P','y','t','h','o','n']
>>> p[2:4] = ['x','y'] # Assigned list is same length as slice
>>> p
['P','y','x','y','o','n'] # Result is same length
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # Assigned list is longer than slice
>>> p
['P','y','t','x','y','o','n'] # The result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
['P','y','t','h','x','y','o','n'] # The result is longer still
Зауважте, що, оскільки ми не змінюємо другий номер фрагмента (4), вставлені елементи завжди укладаються прямо проти 'o', навіть коли ми призначаємо порожній фрагмент. Отже, позиція для призначення порожнього фрагмента - це логічне розширення позицій для призначення не порожнього фрагмента.
Трохи підкріпившись, що станеться, коли ви продовжуєте процес нашого підрахунку часу?
>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
['P','y','t','h']
>>> p[1:4]
['y','t','h']
>>> p[2:4]
['t','h']
>>> p[3:4]
['h']
>>> p[4:4]
[]
>>> p[5:4]
[]
>>> p[6:4]
[]
З нарізкою, як тільки ви закінчите, ви закінчите; вона не починає нарізати назад. У Python ви не отримуєте негативних кроків, якщо ви прямо не попросите їх за допомогою негативного числа.
>>> p[5:3:-1]
['n','o']
Існують деякі дивні наслідки правила "як тільки ти закінчиш, ти закінчиш":
>>> p[4:4]
[]
>>> p[5:4]
[]
>>> p[6:4]
[]
>>> p[6]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
Насправді, порівняно з індексуванням, нарізка Python є химерним чином: помилка:
>>> p[100:200]
[]
>>> p[int(2e99):int(1e99)]
[]
Іноді це може стати в нагоді, але це також може призвести до дещо дивної поведінки:
>>> p
['P', 'y', 't', 'h', 'o', 'n']
>>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
>>> p
['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']
Залежно від вашої заявки, це може бути ... чи не може бути ... тим, на що ви сподівалися там!
Нижче текст моєї оригінальної відповіді. Він був корисний багатьом людям, тому я не хотів його видаляти.
>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]
Це також може уточнити різницю між нарізкою та індексуванням.
Поясніть позначення фрагмента Python
Коротше кажучи, колони ( :
) в індексному позначенні ( subscriptable[subscriptarg]
) робить зріз позначення - у якого є необов'язкові аргументи, start
, stop
, step
:
sliceable[start:stop:step]
Нарізка Python - це обчислювально швидкий спосіб методичного доступу до частин ваших даних. На мою думку, щоб бути навіть проміжним програмістом Python, це один із аспектів мови, з яким потрібно знати.
Для початку давайте визначимося з кількома термінами:
початок: початковий індекс фрагмента, він буде включати елемент цього індексу, якщо він не такий, як зупинка , за замовчуванням 0, тобто перший індекс. Якщо це негативно, це означає починати
n
елементи з кінця.Стоп: індекс закінчення фрагмента, він не включає елемент цього індексу, за замовчуванням до довжини нарізаної послідовності, тобто до кінця, включаючи кінець.
крок: сума, на яку збільшується індекс, за замовчуванням до 1. Якщо вона від’ємна, ви перерізаєте ітерабельний зворотний бік.
Ви можете зробити будь-яке з цих позитивних чи від’ємних чисел. Значення додатних чисел прямо зрозуміло, але для від'ємних чисел, подібно до індексів у Python, ви рахуєте назад від кінця для початку та зупинки , а для кроку ви просто зменшуєте свій індекс. Цей приклад із підручника документації , але я його трохи змінив, щоб вказати на який елемент у послідовності посилається кожен індекс:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
Щоб використовувати позначення зрізів з послідовністю, яка його підтримує, ви повинні включити принаймні одну двокрапку в квадратні дужки, які слідують за послідовністю (що фактично реалізує __getitem__
метод послідовності, відповідно до моделі даних Python .)
Позначення фрагментів працює так:
sequence[start:stop:step]
І пам’ятайте, що для запуску , зупинки та кроку є типові параметри , тому для доступу до значень за замовчуванням просто не залишайте аргумент.
Позначення зрізів для отримання останніх дев'яти елементів зі списку (або будь-якої іншої послідовності, яка його підтримує, як рядок) виглядатиме так:
my_list[-9:]
Коли я це бачу, читаю частину в дужках як "9-ту з кінця, до кінця". (Насправді я подумки скорочую це як «-9, далі»)
Повне позначення є
my_list[-9:None:None]
і підміняти параметри за замовчуванням (насправді, коли step
це мінус, stop
за замовчуванням є -len(my_list) - 1
, тому None
для зупинки дійсно просто означає, що він переходить до того, до якого кроку закінчується крок):
my_list[-9:len(my_list):1]
Товстої кишки , :
є те , що говорить Python , що ви даєте йому шматочок , а не регулярний індекс. Ось чому ідіоматичний спосіб скласти дрібну копію списків у Python 2
list_copy = sequence[:]
І очищення їх здійснюється за допомогою:
del my_list[:]
(Python 3 отримує list.copy
і list.clear
метод.)
step
це негативно, значення за замовчуванням для start
і stop
змінюютьсяЗа замовчуванням, коли step
аргумент порожній (або None
), він призначається +1
.
Але ви можете перейти в негативне ціле число, і список (або більшість інших стандартних складових) буде нарізаний від кінця до початку.
Таким чином, негативний зріз змінить параметри за замовчуванням для start
таstop
!
Мені подобається заохочувати користувачів читати джерело, а також документацію. Тут ви знайдете вихідний код для об'єктів фрагментів і цю логіку . Спочатку визначаємо, чи step
є негативним:
step_is_negative = step_sign < 0;
Якщо так, то нижня межа -1
означає, що ми нарізаємо весь шлях до початку, включаючи початок, а верхня межа - довжина мінус 1, тобто починаємо з кінця. (Зверніть увагу , що семантика цього -1
є відрізняється від А , -1
що користувачі можуть переходити індекси в Python , що вказують на останній елемент.)
if (step_is_negative) { lower = PyLong_FromLong(-1L); if (lower == NULL) goto error; upper = PyNumber_Add(length, lower); if (upper == NULL) goto error; }
В іншому випадку step
є позитивною, а нижня межа буде дорівнює нулю, а верхня межа (до якої ми піднімаємось, але не включає) довжину нарізаного списку.
else { lower = _PyLong_Zero; Py_INCREF(lower); upper = length; Py_INCREF(upper); }
Тоді нам може знадобитися застосувати параметри за замовчуванням для start
та stop
- за замовчуванням тоді для для start
обчислюється як верхня межа, коли step
від'ємне:
if (self->start == Py_None) { start = step_is_negative ? upper : lower; Py_INCREF(start); }
і stop
, нижня межа:
if (self->stop == Py_None) { stop = step_is_negative ? lower : upper; Py_INCREF(stop); }
Вам може бути корисно відокремити формування фрагмента від передачі його list.__getitem__
методу ( саме так роблять квадратні дужки ). Навіть якщо ви не новачок у ньому, він зберігає ваш код читабельнішим, щоб інші, яким, можливо, доведеться читати ваш код, могли легше зрозуміти, що ви робите.
Однак ви не можете просто призначити змінній кілька цілих чисел, розділених двокрапками. Вам потрібно використовувати об’єкт зрізу:
last_nine_slice = slice(-9, None)
Другий аргумент, None
необхідний, так що перший аргумент трактується як start
аргумент, інакше це був би stop
аргумент .
Потім ви можете передати об’єкт фрагмента у свою послідовність:
>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]
Цікаво, що діапазони також беруть фрагменти:
>>> range(100)[last_nine_slice]
range(91, 100)
Оскільки фрагменти списків Python створюють нові об'єкти в пам'яті, ще одна важлива функція, яку слід пам'ятати itertools.islice
. Зазвичай ви хочете перебрати фрагмент, а не просто статично створити його в пам'яті. islice
ідеально підходить для цього. Застереження, воно не підтримує негативні аргументи до start
, stop
або step
, тому якщо це проблема, можливо, вам доведеться заздалегідь обчислити індекси або скасувати ітерабельність.
length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)
і зараз:
>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]
Те, що фрагменти списку роблять копією, є особливістю самих списків. Якщо ви нарізаєте розширені об'єкти, такі як Pandas DataFrame, він може повернути перегляд оригіналу, а не копію.
І ще кілька речей, які мені не були очевидними, коли я вперше побачив синтаксис нарізки:
>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]
Простий спосіб повернути послідовності!
І якщо ви хоч чомусь хотіли, щоб кожен другий елемент у зворотній послідовності:
>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]
У Python 2.7
Нарізка в Python
[a:b:c]
len = length of string, tuple or list
c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.
a -- When c is positive or blank, default is 0. When c is negative, default is -1.
b -- When c is positive or blank, default is len. When c is negative, default is -(len+1).
Розуміння присвоєння індексу є дуже важливим.
In forward direction, starts at 0 and ends at len-1
In backward direction, starts at -1 and ends at -len
Коли ви говорите [a: b: c], ви говорите, залежно від знаку c (вперед або назад), починайте з a і закінчуйте з b (виключаючи елемент у bth індексі). Скористайтеся правилом індексації вище та пам’ятайте, що ви знайдете лише елементи в цьому діапазоні:
-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1
Але цей діапазон триває в обох напрямках нескінченно:
...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....
Наприклад:
0 1 2 3 4 5 6 7 8 9 10 11
a s t r i n g
-9 -8 -7 -6 -5 -4 -3 -2 -1
Якщо ваш вибір a, b і c дозволяє збігатися з вищезазначеним діапазоном, коли ви переходите, використовуючи правила для a, b, c вище, ви або отримаєте список з елементами (торкнувся під час обходу), або ви отримаєте порожній список.
Останнє: якщо a і b рівні, то ви також отримаєте порожній список:
>>> l1
[2, 3, 4]
>>> l1[:]
[2, 3, 4]
>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]
>>> l1[:-4:-1] # a default is -1
[4, 3, 2]
>>> l1[:-3:-1] # a default is -1
[4, 3]
>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]
>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]
>>> l1[-100:-200:-1] # Interesting
[]
>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]
>>> l1[-1:-1:1]
[]
>>> l1[-1:5:1] # Interesting
[4]
>>> l1[1:-7:1]
[]
>>> l1[1:-7:-1] # Interesting
[3, 2]
>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]
a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]
результат[9]
Знайшов цей чудовий стіл на http://wiki.python.org/moin/MovingToPythonFromOtherLanguages
Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.
Index from rear: -6 -5 -4 -3 -2 -1 a=[0,1,2,3,4,5] a[1:]==[1,2,3,4,5]
Index from front: 0 1 2 3 4 5 len(a)==6 a[:5]==[0,1,2,3,4]
+---+---+---+---+---+---+ a[0]==0 a[:-2]==[0,1,2,3]
| a | b | c | d | e | f | a[5]==5 a[1:2]==[1]
+---+---+---+---+---+---+ a[-1]==5 a[1:-1]==[1,2,3,4]
Slice from front: : 1 2 3 4 5 : a[-2]==4
Slice from rear: : -5 -4 -3 -2 -1 :
b=a[:]
b==[0,1,2,3,4,5] (shallow copy of a)
Трохи використавши його, я зрозумів, що найпростіший опис полягає в тому, що він точно такий же, як аргументи в for
циклі ...
(from:to:step)
Будь-який із них не є обов'язковим:
(:to:step)
(from::step)
(from:to)
Тоді негативне індексування просто потрібно, щоб ви додали довжину рядка до негативних індексів, щоб зрозуміти це.
Це все одно для мене працює ...
Мені легше запам'ятати, як це працює, і тоді я можу визначити будь-яку конкретну комбінацію старт / стоп / крок.
Потрібно зрозуміти range()
спочатку:
def range(start=0, stop, step=1): # Illegal syntax, but that's the effect
i = start
while (i < stop if step > 0 else i > stop):
yield i
i += step
Почніть з start
приросту step
, не досягайте stop
. Дуже просто.
Що слід пам'ятати про негативний крок, це те, що stop
це завжди виключений кінець, будь він вищий чи нижчий. Якщо ви хочете той самий зріз у зворотному порядку, набагато чистіше робити реверс окремо: наприклад, 'abcde'[1:-2][::-1]
відрізати один знак зліва, два праворуч, а потім перевернути. (Див. Також reversed()
.)
Нарізка послідовності однакова, за винятком того, що вона спочатку нормалізує негативні показники, і вона ніколи не може вийти за межі послідовності
TODO : У наведеному нижче коді виникла помилка з "ніколи не виходити за межі послідовності", коли abs (крок)> 1; Я думаю, що я зафіксував це як правильно, але важко зрозуміти.
def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
if start is None:
start = (0 if step > 0 else len(seq)-1)
elif start < 0:
start += len(seq)
if not 0 <= start < len(seq): # clip if still outside bounds
start = (0 if step > 0 else len(seq)-1)
if stop is None:
stop = (len(seq) if step > 0 else -1) # really -1, not last element
elif stop < 0:
stop += len(seq)
for i in range(start, stop, step):
if 0 <= i < len(seq):
yield seq[i]
Не турбуйтеся про is None
деталі - просто пам’ятайте, що пропускаючи start
та / або stop
завжди робите правильно, щоб дати вам всю послідовність.
Нормалізація від'ємних індексів спочатку дозволяє самостійно рахувати старт та / або зупинку: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'
незважаючи на це range(1,-2) == []
. Нормалізацію іноді розглядають як "модульну довжину", але зауважте, що вона додає довжину лише один раз: наприклад, 'abcde'[-53:42]
це лише весь рядок.
this_is_how_slicing_works
не те саме, що пітон шматочок. EG [0, 1, 2][-5:3:3]
отримає [0] в python, але list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))
отримає [1].
range(4)[-200:200:3] == [0, 3]
але list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]
. Моєю if 0 <= i < len(seq):
була спроба реалізувати "ніколи не виходити за межі послідовності" просто, але неправильно для кроку> 1. Я перепишу це пізніше сьогодні (з тестами).
Index:
------------>
0 1 2 3 4
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
0 -4 -3 -2 -1
<------------
Slice:
<---------------|
|--------------->
: 1 2 3 4 :
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
: -4 -3 -2 -1 :
|--------------->
<---------------|
Я сподіваюся, що це допоможе вам моделювати список у Python.
Довідка: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages
Позначення нарізки пітона:
a[start:end:step]
start
іend
, негативні значення інтерпретуються як відносні до кінця послідовності.end
позначення позиції після включення останнього елемента.[+0:-0:1]
.start
таend
Позначення поширюється на (numpy) матриці та багатовимірні масиви. Наприклад, для розрізання цілих стовпців ви можете використовувати:
m[::,0:2:] ## slice the first two columns
У фрагментах містяться посилання, а не копії елементів масиву. Якщо ви хочете зробити окрему копію масиву, ви можете використовувати deepcopy()
.
Це лише для додаткової інформації ... Розгляньте список нижче
>>> l=[12,23,345,456,67,7,945,467]
Кілька інших хитрощів для повернення списку:
>>> l[len(l):-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[len(l)::-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[::-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[-1:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
Ось як я вчу скибочок для новачків:
Розуміння різниці між індексуванням та нарізкою:
У Wiki Python є ця дивовижна картина, яка чітко відрізняє індексацію та нарізку.
Це список із шістьма елементами. Щоб краще зрозуміти нарізку, розгляньте цей список як набір із шести коробок, розміщених разом. Кожен ящик має в ньому алфавіт.
Індексація схожа на справу зі змістом поля. Ви можете перевірити вміст будь-якого вікна. Але ви не можете перевірити вміст декількох коробок одночасно. Можна навіть замінити вміст коробки. Але ви не можете помістити дві кульки в одну коробку або замінити дві кульки одночасно.
In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [123]: alpha
Out[123]: ['a', 'b', 'c', 'd', 'e', 'f']
In [124]: alpha[0]
Out[124]: 'a'
In [127]: alpha[0] = 'A'
In [128]: alpha
Out[128]: ['A', 'b', 'c', 'd', 'e', 'f']
In [129]: alpha[0,1]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-129-c7eb16585371> in <module>()
----> 1 alpha[0,1]
TypeError: list indices must be integers, not tuple
Нарізання подібне до роботи з самими ящиками. Ви можете забрати перший ящик і помістити його на інший стіл. Щоб забрати коробку, все, що вам потрібно знати, - це позиція початку та кінця коробки.
Ви навіть можете забрати перші три ящики або дві останні ящики або всі ящики між 1 і 4. Отже, ви можете вибрати будь-який набір коробок, якщо знаєте початок і кінець. Ці позиції називаються позиціями старту та зупинки.
Цікавим є те, що ви можете замінити відразу кілька коробок. Крім того, ви можете розмістити декілька коробок де завгодно.
In [130]: alpha[0:1]
Out[130]: ['A']
In [131]: alpha[0:1] = 'a'
In [132]: alpha
Out[132]: ['a', 'b', 'c', 'd', 'e', 'f']
In [133]: alpha[0:2] = ['A', 'B']
In [134]: alpha
Out[134]: ['A', 'B', 'c', 'd', 'e', 'f']
In [135]: alpha[2:2] = ['x', 'xx']
In [136]: alpha
Out[136]: ['A', 'B', 'x', 'xx', 'c', 'd', 'e', 'f']
Нарізка кроком:
До цього часу ви постійно збирали коробки. Але іноді потрібно підбирати дискретно. Наприклад, ви можете забрати кожну другу коробку. Можна навіть забрати кожну третю скриньку з кінця. Це значення називається розміром кроку. Це являє собою розрив між вашими послідовними підборами. Розмір кроку повинен бути позитивним, якщо ви збираєте коробки від початку до кінця і навпаки.
In [137]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [142]: alpha[1:5:2]
Out[142]: ['b', 'd']
In [143]: alpha[-1:-5:-2]
Out[143]: ['f', 'd']
In [144]: alpha[1:5:-2]
Out[144]: []
In [145]: alpha[-1:-5:2]
Out[145]: []
Як Python з'ясовує пропущені параметри:
Під час нарізки, якщо ви не залишите жоден параметр, Python намагається визначити його автоматично.
Якщо ви перевірите вихідний код CPython , ви знайдете функцію під назвою PySlice_GetIndicesEx (), яка визначає індекси до фрагменту для будь-яких заданих параметрів. Ось логічний еквівалентний код у Python.
Ця функція приймає об'єкт Python та необов'язкові параметри для нарізки та повертає довжину початку, зупинки, кроку та фрагмента для запитуваного фрагмента.
def py_slice_get_indices_ex(obj, start=None, stop=None, step=None):
length = len(obj)
if step is None:
step = 1
if step == 0:
raise Exception("Step cannot be zero.")
if start is None:
start = 0 if step > 0 else length - 1
else:
if start < 0:
start += length
if start < 0:
start = 0 if step > 0 else -1
if start >= length:
start = length if step > 0 else length - 1
if stop is None:
stop = length if step > 0 else -1
else:
if stop < 0:
stop += length
if stop < 0:
stop = 0 if step > 0 else -1
if stop >= length:
stop = length if step > 0 else length - 1
if (step < 0 and stop >= start) or (step > 0 and start >= stop):
slice_length = 0
elif step < 0:
slice_length = (stop - start + 1)/(step) + 1
else:
slice_length = (stop - start - 1)/(step) + 1
return (start, stop, step, slice_length)
Це інтелект, який присутній за шматочками. Оскільки в Python є вбудована функція, яка називається фрагмент, ви можете передавати деякі параметри і перевірити, наскільки розумно він обчислює відсутні параметри.
In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [22]: s = slice(None, None, None)
In [23]: s
Out[23]: slice(None, None, None)
In [24]: s.indices(len(alpha))
Out[24]: (0, 6, 1)
In [25]: range(*s.indices(len(alpha)))
Out[25]: [0, 1, 2, 3, 4, 5]
In [26]: s = slice(None, None, -1)
In [27]: range(*s.indices(len(alpha)))
Out[27]: [5, 4, 3, 2, 1, 0]
In [28]: s = slice(None, 3, -1)
In [29]: range(*s.indices(len(alpha)))
Out[29]: [5, 4]
Примітка. Ця публікація спочатку була написана в моєму блозі "Розвідка за фрагментами пітона" .
Як правило, написання коду з великою кількістю твердо кодованих значень індексу призводить до зручності читання та обслуговування. Наприклад, якщо через рік ви повернетесь до коду, ви подивитесь на нього і здивуєтеся, що ви думали, коли його писали. Показане рішення - це просто спосіб більш чітко визначити, чим насправді займається ваш код. Взагалі, вбудований фрагмент () створює об'єкт фрагмента, який можна використовувати де завгодно. Наприклад:
>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]
Якщо у вас є екземпляр зрізу, ви можете отримати більше інформації про нього, переглянувши його атрибути s.start, s.stop та s.step відповідно. Наприклад:
>>> a = slice(10, 50, 2) >>> a.start 10 >>> a.stop 50 >>> a.step 2 >>>
Щоб зробити це просто, пам’ятайте, що фрагмент має лише одну форму:
s[start:end:step]
і ось як це працює:
s
: предмет, який можна нарізатиstart
: перший індекс для запуску ітераціїend
: останній індекс, Зверніть увагу, що end
індекс не буде включений до результатуstep
: вибрати елемент кожного step
індексуІнший імпорт річ: все start
, end
, step
може бути опущена! І якщо вони опущені, буде використано їх значення по замовчуванням: 0
, len(s)
,1
відповідно.
Тому можливі варіанти:
# Mostly used variations
s[start:end]
s[start:]
s[:end]
# Step-related variations
s[:end:step]
s[start::step]
s[::step]
# Make a copy
s[:]
ПРИМІТКА: Якщо start >= end
(враховуючи лише коли step>0
), Python поверне порожній фрагмент[]
.
Вищевказана частина пояснює основні особливості того, як працює фрагмент, і він буде працювати в більшості випадків. Однак можуть бути підводні камені, на які слід стежити, і ця частина пояснює їх.
Найперше, що бентежить учнів Python, - це те, що індекс може бути негативним! Не панікуйте: від'ємний індекс означає підрахунок назад.
Наприклад:
s[-5:] # Start at the 5th index from the end of array,
# thus returning the last 5 elements.
s[:-5] # Start at index 0, and end until the 5th index from end of array,
# thus returning s[0:len(s)-5].
Зробити речі більш заплутаними - це теж step
може бути негативно!
Негативний крок означає ітерацію масиву назад: від кінця до початку, з включеним кінцевим індексом, а індекс запуску виключений з результату.
Примітка : якщо крок від'ємний, значення за замовчуванням start
є len(s)
(поки end
не складе 0
, так як s[::-1]
містить s[0]
). Наприклад:
s[::-1] # Reversed slice
s[len(s)::-1] # The same as above, reversed slice
s[0:len(s):-1] # Empty list
Будьте здивовані: фрагмент не піднімає IndexError, коли індекс знаходиться поза діапазоном!
Якщо індекс виходить за допустимі, Python буде намагатися все можливе , щоб встановити індекс 0
або в len(s)
залежності від ситуації. Наприклад:
s[:len(s)+5] # The same as s[:len(s)]
s[-len(s)-5::] # The same as s[0:]
s[len(s)+5::-1] # The same as s[len(s)::-1], and the same as s[::-1]
Давайте закінчимо цю відповідь на прикладах, пояснивши все, що ми обговорили:
# Create our array for demonstration
In [1]: s = [i for i in range(10)]
In [2]: s
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: s[2:] # From index 2 to last index
Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]
In [4]: s[:8] # From index 0 up to index 8
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]
In [5]: s[4:7] # From index 4 (included) up to index 7(excluded)
Out[5]: [4, 5, 6]
In [6]: s[:-2] # Up to second last index (negative index)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]
In [7]: s[-2:] # From second last index (negative index)
Out[7]: [8, 9]
In [8]: s[::-1] # From last to first in reverse order (negative step)
Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [9]: s[::-2] # All odd numbers in reversed order
Out[9]: [9, 7, 5, 3, 1]
In [11]: s[-2::-2] # All even numbers in reversed order
Out[11]: [8, 6, 4, 2, 0]
In [12]: s[3:15] # End is out of range, and Python will set it to len(s).
Out[12]: [3, 4, 5, 6, 7, 8, 9]
In [14]: s[5:1] # Start > end; return empty list
Out[14]: []
In [15]: s[11] # Access index 11 (greater than len(s)) will raise an IndexError
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]
IndexError: list index out of range
Попередні відповіді не обговорюють розмірність багатовимірного масиву, який можливий за допомогою відомого пакету NumPy :
Нарізка також може застосовуватися до багатовимірних масивів.
# Here, a is a NumPy array
>>> a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
>>> a[:2, 0:3:2]
array([[1, 3],
[5, 7]])
" :2
" Перед комою оперує перший вимір, а " 0:3:2
" після коми працює над другим виміром.
list
а лише array
в Numpy
#!/usr/bin/env python
def slicegraphical(s, lista):
if len(s) > 9:
print """Enter a string of maximum 9 characters,
so the printig would looki nice"""
return 0;
# print " ",
print ' '+'+---' * len(s) +'+'
print ' ',
for letter in s:
print '| {}'.format(letter),
print '|'
print " ",; print '+---' * len(s) +'+'
print " ",
for letter in range(len(s) +1):
print '{} '.format(letter),
print ""
for letter in range(-1*(len(s)), 0):
print ' {}'.format(letter),
print ''
print ''
for triada in lista:
if len(triada) == 3:
if triada[0]==None and triada[1] == None and triada[2] == None:
# 000
print s+'[ : : ]' +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] == None and triada[1] == None and triada[2] != None:
# 001
print s+'[ : :{0:2d} ]'.format(triada[2], '','') +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] == None and triada[1] != None and triada[2] == None:
# 010
print s+'[ :{0:2d} : ]'.format(triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] == None and triada[1] != None and triada[2] != None:
# 011
print s+'[ :{0:2d} :{1:2d} ]'.format(triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] == None and triada[2] == None:
# 100
print s+'[{0:2d} : : ]'.format(triada[0]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] == None and triada[2] != None:
# 101
print s+'[{0:2d} : :{1:2d} ]'.format(triada[0], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] != None and triada[2] == None:
# 110
print s+'[{0:2d} :{1:2d} : ]'.format(triada[0], triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] != None and triada[2] != None:
# 111
print s+'[{0:2d} :{1:2d} :{2:2d} ]'.format(triada[0], triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif len(triada) == 2:
if triada[0] == None and triada[1] == None:
# 00
print s+'[ : ] ' + ' = ', s[triada[0]:triada[1]]
elif triada[0] == None and triada[1] != None:
# 01
print s+'[ :{0:2d} ] '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]
elif triada[0] != None and triada[1] == None:
# 10
print s+'[{0:2d} : ] '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]
elif triada[0] != None and triada[1] != None:
# 11
print s+'[{0:2d} :{1:2d} ] '.format(triada[0],triada[1]) + ' = ', s[triada[0]:triada[1]]
elif len(triada) == 1:
print s+'[{0:2d} ] '.format(triada[0]) + ' = ', s[triada[0]]
if __name__ == '__main__':
# Change "s" to what ever string you like, make it 9 characters for
# better representation.
s = 'COMPUTERS'
# add to this list different lists to experement with indexes
# to represent ex. s[::], use s[None, None,None], otherwise you get an error
# for s[2:] use s[2:None]
lista = [[4,7],[2,5,2],[-5,1,-1],[4],[-4,-6,-1], [2,-3,1],[2,-3,-1], [None,None,-1],[-5,None],[-5,0,-1],[-5,None,-1],[-1,1,-2]]
slicegraphical(s, lista)
Ви можете запустити цей скрипт і експериментувати з ним, нижче наведено кілька зразків, які я отримав із сценарію.
+---+---+---+---+---+---+---+---+---+
| C | O | M | P | U | T | E | R | S |
+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
-9 -8 -7 -6 -5 -4 -3 -2 -1
COMPUTERS[ 4 : 7 ] = UTE
COMPUTERS[ 2 : 5 : 2 ] = MU
COMPUTERS[-5 : 1 :-1 ] = UPM
COMPUTERS[ 4 ] = U
COMPUTERS[-4 :-6 :-1 ] = TU
COMPUTERS[ 2 :-3 : 1 ] = MPUT
COMPUTERS[ 2 :-3 :-1 ] =
COMPUTERS[ : :-1 ] = SRETUPMOC
COMPUTERS[-5 : ] = UTERS
COMPUTERS[-5 : 0 :-1 ] = UPMO
COMPUTERS[-5 : :-1 ] = UPMOC
COMPUTERS[-1 : 1 :-2 ] = SEUM
[Finished in 0.9s]
Використовуючи негативний крок, зверніть увагу, що відповідь зміщено вправо на 1.
Мій мозок здається щасливим прийняти, що 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
.
На мою думку, ви краще зрозумієте і запам’ятаєте нотацію нарізки рядка 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.
Пам'ятайте, що ми встановлюємо межі. І ці межі - це позиції, де ви можете розмістити кілька дужок, які будуть обернуті навколо підрядок таким чином ...
ab [ cdefgh ] ij
Цей трюк працює весь час і його легко запам’ятати.
Більшість попередніх відповідей очищає питання щодо позначення фрагментів.
Розширений синтаксис індексації, який використовується для нарізки, є aList[start:stop:step]
основними прикладами:
Більше прикладів нарізки: 15 розширених фрагментів
У 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 three elements
Out[8]: [7, 8, 9]
При нарізанні можна надати показники, які не виходять за межі, такі як:
In [9]: l[:20] # 20 is out of index bounds, and 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, and 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 fewer 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
це крок, який можна використовувати для отримання кожного n-го елемента 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
може стати дуже заплутаним. Крім того, для того , щоб бути віщим , слід уникати використання 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]
Я хочу додати один 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']
.
Нижче наведено приклад індексу рядка:
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
str="Name string"
Приклад нарізки: [start: end: step]
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
Якщо ви вважаєте, що негативні показники нарізки є заплутаними, ось дуже простий спосіб подумати над цим: просто замініть негативний індекс на 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 a for-loop with start, end and step
return [list[i] for i in range(start, end, step)]
Основна техніка нарізки - визначити початкову точку, точку зупинки та розмір кроку - також відомий як крок.
По-перше, ми створимо список значень, які слід використовувати в нашій нарізці.
Створіть два списки для скибочки. Перший - це числовий список від 1 до 9 (Список А). Другий - це також числовий список від 0 до 9 (Список В):
A = list(range(1, 10, 1)) # Start, stop, and 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]. Аргумент старту і крок аргумент за замовчуванням - немає, єдиний необхідний аргумент - стоп. Ви помітили, що це схоже на те, як діапазон використовувався для визначення списків А і В? Це відбувається тому, що об'єкт зрізу представляє набір індексів, визначених діапазоном (початок, зупинка, крок). Документація Python 3.4.
Як бачите, визначення лише стоп повертає один елемент. Оскільки початкові настройки за замовчуванням є жодними, це перетворюється на отримання лише одного елемента.
Важливо зауважити, перший елемент - індекс 0, а не індекс 1. Ось чому для цієї вправи ми використовуємо 2 списки. Елементи списку А нумеруються відповідно до порядкового положення (перший елемент - 1, другий - 2 і т.д.), тоді як елементи списку В - це числа, які будуть використані для їх індексації ([0] для першого елемента 0, тощо).
За допомогою розширеного синтаксису індексації ми отримуємо діапазон значень. Наприклад, усі значення отримані двокрапкою.
A[:]
Щоб отримати підмножину елементів, потрібно визначити положення старту та зупинки.
З огляду на шаблон aList [start: stop], отримайте перші два елементи зі списку A.
Я не думаю, що схема підручника Python (цитується в різних інших відповідях) хороша, оскільки ця пропозиція працює в позитивному кроці, але не має негативного кроку.
Це схема:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
З діаграми я очікую, a[-4,-6,-1]
що вона буде, yP
але вона є ty
.
>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'
Що завжди працює - це мислити символами чи слотами та використовувати індексацію як напіввідкритий інтервал - справа-відкрито, якщо позитивний крок, ліво-відкрито, якщо негативний крок.
Таким чином, я можу думати , a[-4:-6:-1]
як a(-6,-4]
в інтервального термінології.
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
+---+---+---+---+---+---+---+---+---+---+---+---+
| P | y | t | h | o | n | P | y | t | h | o | n |
+---+---+---+---+---+---+---+---+---+---+---+---+
-6 -5 -4 -3 -2 -1 0 1 2 3 4 5