Расширенный срез, который начинается с начала последовательности с отрицательным шагом

Потерпите меня, пока я объясню свой вопрос. Перейдите к жирному заголовку, если вы уже понимаете индексирование расширенного списка фрагментов.

В python вы можете индексировать списки с использованием нотации среза. Вот пример:

>>> A = list(range(10))
>>> A[0:5]
[0, 1, 2, 3, 4]

Вы также можете включить шаг, который действует как "шаг":

>>> A[0:5:2]
[0, 2, 4]

Штраф также может быть отрицательным, что означает, что элементы извлекаются в обратном порядке:

>>> A[5:0:-1]
[5, 4, 3, 2, 1]

Но подождите! Я хотел увидеть [4, 3, 2, 1, 0]. О, я вижу, мне нужно уменьшить начальные и конечные индексы:

>>> A[4:-1:-1]
[]

Что случилось? Он интерпретирует -1 как находящийся в конце массива, а не в начале. Я знаю, что вы можете достичь этого следующим образом:

>>> A[4::-1]
[4, 3, 2, 1, 0]

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

Мой вопрос:

Есть ли какой-либо хороший питонический способ использования расширенных срезов с отрицательными шагами и явных начальных и конечных индексов, которые включают первый элемент последовательности?

Это то, к чему я придумал, но кажется неудовлетворительным.

>>> A[0:5][::-1]
[4, 3, 2, 1, 0]

Ответ 1

Хорошо, я думаю, что это, вероятно, так хорошо, как я его получу. Спасибо Абгану за то, что он вызвал эту идею. Это зависит от того, что None в срезе обрабатывается так, как если бы это был отсутствующий параметр. Кто-нибудь получил что-то лучше?

def getReversedList(aList, end, start, step):
    return aList[end:start if start!=-1 else None:step]

edit: проверьте start==-1, а не 0

Это все еще не идеально, потому что вы clobbering обычное поведение -1. Кажется, проблема здесь состоит в двух совпадающих определениях того, что должно было случиться. Тот, кто побеждает, убирает в противном случае действительные призывы, ища другое намерение.

Ответ 2

Склонность к изменению семантики start и stop может быть подвержена ошибкам. Используйте None или -(len(a) + 1) вместо 0 или -1. Семантика не является произвольной. См. Статью Edsger W. Dijkstra "Почему нумерация должна начинаться с нуля" .

>>> a = range(10)
>>> start, stop, step = 4, None, -1

Или

>>> start, stop, step = 4, -(len(a) + 1), -1
>>> a[start:stop:step]
[4, 3, 2, 1, 0]

или

>>> s = slice(start, stop, step)
>>> a[s]
[4, 3, 2, 1, 0]

Когда s представляет собой последовательность, отрицательные индексы в s[i:j:k] обрабатываются специально:

Если i или j является отрицательным, индекс относится к концу строки: len(s) + i или len(s) + j. Но учтите, что -0 все еще 0.

поэтому len(range(10)[4:-1:-1]) == 0, потому что он эквивалентен range(10)[4:9:-1].

Ответ 3

[ A[b] for b in range(end,start,stride) ]

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

[ A[b] for b in range(9, -1, -1) ]

Я понимаю, что это не использование срезов, но я думал, что предлагаю решение в любом случае, если использование срезов специально для получения результата не является приоритетом.

Ответ 4

Я считаю, что следующее вас не удовлетворяет:

def getReversedList(aList, end, start, step):
    if step < 0 and start == 0:
         return aList[end::step]
    return aList[end:start:step]

или он?: -)

Ответ 5

Но вы не можете использовать это, если вы сохранение ваших индексов в переменных для Пример.

Это удовлетворительно?

>>> a = range(10)
>>> start = 0
>>> end = 4
>>> a[4:start-1 if start > 0 else None:-1]
[4, 3, 2, 1, 0]

Ответ 6

Как вы говорите, очень немногие люди полностью понимают все, что вы можете сделать с расширенной срезкой, поэтому, если вам действительно не нужна дополнительная производительность, я бы сделал это "очевидным" способом:

rev_subset = reversed(data[start:stop])

Ответ 7

a[4::-1]

Пример:

Python 2.6 (r26:66714, Dec  4 2008, 11:34:15) 
[GCC 4.0.1 (Apple Inc. build 5488)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[4:0:-1]
[4, 3, 2, 1]
>>> a[4::-1]
[4, 3, 2, 1, 0]
>>> 

Причина в том, что второй термин интерпретируется как "while not index ==". Выход из него - это "пока индекс в диапазоне".

Ответ 8

Я знаю, что это старый вопрос, но если кто-то вроде меня ищет ответы:

>>> A[5-1::-1]
[4, 3, 2, 1, 0]

>>> A[4:1:-1]
[4, 3, 2]

Ответ 9

Вы можете использовать объект slice(start, stop, step), который таков, что

s=slice(start, stop, step)
print a[s]

совпадает с

print a[start : stop : step]

и, кроме того, вы можете установить любой из аргументов None, чтобы ничего не указывать между двоеточиями. Итак, в случае, которое вы даете, вы можете использовать slice(4, None, -1).