Переворачивание списка с использованием нотации срезов

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] не печатает весь список ?

user737079
источник
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> ]самое ясное объяснение синтаксиса срезов, которое я видел. Назвав его «первым исключаемым элементом», действительно становится очевидным, что происходит.
Schof 05
А как насчет отрицательного среза с отрицательными шагами? Я все еще не понимаю.
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 08
1
Как сделать так, чтобы первый элемент исключал «предшествующий элемент foo[0]»?
BallpointBen
9

Если у вас возникли проблемы с запоминанием нотации срезов, вы можете попробовать выполнить Hokey Cokey :

[ In : Out : Shake all about ]

[Первый элемент в заключить , : первый элемент , чтобы выйти из : The шаг к использованию]

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может, но slice не может, потому что -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 как особый случай.
Tom Zych
Это имеет больше смысла, чем поведение Python / numpy по умолчанию для отрицательной нарезки, потому что обычно требуется нарезать и / или инвертировать изображение или тензор, выровненный по заданному краю, тогда как Python / numpy теряет эту последнюю строку / столбец данных o_O.
Дуэйн Робинсон,
1

Использовать

>>>foo[::-1]

Это отображает обратную сторону списка от конечного элемента до начала,

Ашмита Датта
источник
1

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

foo[-1:-7:-1]
myQwil
источник
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

формализуя ответ Эндрю-Кларка еще немного:

Допустим список 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)

Пауло Бухсбаум
источник