Зміна списку за допомогою позначення фрагментів


80

у наступному прикладі:

foo = ['red', 'white', 'blue', 1, 2, 3]

де: foo[0:6:1]буде друкувати всі елементи у foo. Однак foo[6:0:-1]буде опущено 1-й або 0-й елемент.

>>> foo[6:0:-1]
[3, 2, 1, 'blue', 'white']

Я розумію, що можу використовувати foo.reverse () або foo [:: - 1] для друку списку в зворотному порядку, але я намагаюся зрозуміти, чому foo [6: 0: -1] не друкує весь список ?


3
Зверніть увагу також на foo[7:None:-1]можливість :)
tzot

1
Я ніколи не використовував python, перш ніж просто намагався зрозуміти нотацію зрізів, моє питання полягає в тому, чому foo [6: 0: -1] не викидає помилку індексу, чи python про це не піклується? оскільки індекс 6 недоступний у наведеному вище прикладі масиву.
Мубашар,

3
@MubasharAhmad Slicing не індексує і не викидає жодної помилки, коли виходить за межі. Однак індексація викидає винятки, коли поза межами.
huggie

Відповіді:


152

Коротке позначення фрагмента:

[ <first element to include> : <first element to exclude> : <step> ]

Якщо ви хочете включити перший елемент при обертанні списку, залиште середній елемент порожнім, наприклад:

foo[::-1]

Ви також можете знайти хорошу інформацію про фрагменти Python загалом тут:
Поясніть позначення фрагментів Python


42
Це: [ <first element to include> : <first element to exclude> : <step> ]це найбільш чітке пояснення синтаксису фрагмента, яке я бачив. Називаючи його "першим елементом для виключення", насправді стає очевидним, що відбувається.
Шоф

А як щодо негативного нарізання з негативними кроками? Я все ще не розумію.
huggie

6
Коли ви використовуєте від'ємний індекс як будь-який, <first element to include>або <first element to exclude>він індексується із зворотного боку списку, так само -1є останній елемент, -2є другим до останнього елемента і т. Д. Так, наприклад, x[-1:-4:-1]отримаємо останні три елементи xв зворотному порядку. Тому ви можете інтерпретувати це як "рухаючись назад, виконайте кожен елемент ( -1крок) від останнього елемента у списку ( -1 <first element to include>) до, але не включаючи четвертий елемент від кінця ( -4 <first element to include>)".
Ендрю Кларк

1
Під час руху заднім ходом (тобто, якщо <step>є -1), це допомагає мені думати <first element to include, moving from right to left>. Таким чином, щоб отримати n«ліві» елементи зі списку в зворотному порядку: foo[n-1::-1]. Для того, щоб отримати n«праві» елементи в зворотному порядку: foo[-1:-n-1:-1].
djvg

1
Як зробити так, щоб перший елемент виключив "елемент до foo[0]"?
BallpointBen

9

Якщо у вас виникають проблеми з запам'ятовуванням нотації фрагментів, ви можете спробувати виконати Hokey Cokey :

[ In : Out : Shake it about about ]

[Перший елемент в укласти , : перший елемент , щоб залишити з : крок до використання]

YMMV


7

... чому foo [6: 0: -1] не друкує весь список?

Оскільки середнє значення - це ексклюзивне , а не інклюзивне, стоп-значення. Інтервал позначення є [старт, стоп).

Саме так працює діапазон [x]:

>>> range(6, 0, -1)
[6, 5, 4, 3, 2, 1]

Це показники, які включаються у ваш підсумковий список, і вони не включають 0 для першого елемента.

>>> range(6, -1, -1)
[6, 5, 4, 3, 2, 1, 0]

Інший спосіб подивитися на це:

>>> L = ['red', 'white', 'blue', 1, 2, 3]
>>> L[0:6:1]
['red', 'white', 'blue', 1, 2, 3]
>>> len(L)
6
>>> L[5]
3
>>> L[6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

Індекс 6 виходить за рамки (точно минулих, точно) дійсних індексів для L, тому виключаючи його з діапазону як виключене значення зупинки:

>>> range(0, 6, 1)
[0, 1, 2, 3, 4, 5]

Все ще дає вам індекси для кожного елемента у списку.


1
rangeможе це зробити, але фрагмент не може, тому що -1це останній елемент. Так l=[1, 2, 3], l[2:-1:-1] == [].
Simin Jie

6

Ця відповідь може бути трохи застарілою, але може бути корисною для тих, хто стикається з такою ж проблемою. Ви можете отримати зворотний список з довільним кінцем - до 0 індексу, застосовуючи другий фрагмент на місці, як це:

>>> L = list(range(10))
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> (start_ex, end) = (7, 0)
>>> L[end:start_ex][::-1]
[6, 5, 4, 3, 2, 1, 0]

1
Це насправді досить корисно, оскільки ви можете використовувати однаковий синтаксис для всіх випадків. Вам не потрібно розглядати 0 як особливий випадок.
Том Зич

Це має більше сенсу, ніж поведінка за замовчуванням Python / numpy для негативного нарізання, оскільки зазвичай вони хочуть нарізати та / або змінити зображення або тензор, вирівняні до даного краю, тоді як Python / numpy втрачають останній рядок / стовпець даних o_O.
Дуейн Робінсон

1

Використовуйте

>>>foo[::-1]

Це відображає зворотний бік списку від кінця елемента до початку,


1

Ви можете змусити його працювати, якщо використовуєте від’ємне значення зупинки. Спробуйте це:

foo[-1:-7:-1]

0

Доповнення. повернути крок назад на 2:

A = [1,2,2,3,3]
n = len(A)
res = [None] * n
mid = n//2 + 1 if n%2 == 1 else n//2

res[0::2] = A[0:mid][::-1]
res[1::2] = A[0:mid][::-1]
print(res)

[2, 3, 2, 3, 1]


0

ще трохи формалізувавши відповідь від andrew-clark :

Припустимо, список vі v[n1:n2:n3]фрагмент. n1початкове положення, n2кінцеве положення і n3крок

Давайте напишемо якийсь псевкод способом Python:

n3 = 1  if (n3 is missing) else n3
if n3==0:
   raise exception # error, undefined step

Перша частина: n3 позитивна

if n3>0:
   slice direction is from left to right, the most common direction         

   n1 is left slice position in `v` 
   if n1 is missing: 
      n1 = 0   # initial position
   if n1>=0:
      n1 is a normal position
   else: 
     (-n1-1) is the position in the list from right to left 

   n2 is right slice position in `v` 
   if n2 is missing: 
      n2 = len(x)  # after final position
   if n2>=0:
      n2 is a normal final position (exclusive)
   else: 
      -n2-1 é the final position in the list from right to left 
       (exclusive)

Друга частина: n3 негативна

else: 
  slice direction is from right to left (inverse direction)

  n1 is right slice position in `v` 
  if n1 is missing: 
     n1 = -1   # final position is last position in the list.
  if n1>=0:
     n1 is a normal position
  else: 
     (-n1-1) is the position in the list from right to left 

  n2 is  left slice position in `v` 
  if n2 is missing: 
     n2 = -len(x)-1   # before 1st character  (exclusive)
  if n2>=0:
     n2 is a normal final position (exclusive)
  else: 
     -n2-1 is the ending position in the list from right to left 
     (exclusive)

Тепер оригінальна проблема: Як змінити список із позначеннями зрізів?

L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(L(::-1)) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Чому?
n1 is missing and n3<0 => n1=0
n2 is missing and n3<0 => n2 = -len(x)-1

Так L(::-1) == L(-1:-11:-1)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.