Расширенный фрагмент, который идет в начало последовательности с отрицательным шагом - PullRequest
13 голосов
/ 30 декабря 2008

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

В 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]

Ответы [ 9 ]

5 голосов
/ 30 декабря 2008

Чрезвычайно подвержено ошибкам изменение семантики start и stop. Используйте None или -(len(a) + 1) вместо 0 или -1. Семантика не произвольна. См. Статью Эдсгера В. Дейкстры «Почему нумерация должна начинаться с нуля» .

>>> 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].

2 голосов
/ 30 декабря 2008
[ A[b] for b in range(end,start,stride) ]

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

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

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

2 голосов
/ 30 декабря 2008

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

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

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

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

1 голос
/ 30 декабря 2008

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

rev_subset = reversed(data[start:stop])

1 голос
/ 30 декабря 2008

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

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

>>> a = range(10)
>>> start = 0
>>> end = 4
>>> a[4:start-1 if start > 0 else None:-1]
[4, 3, 2, 1, 0]
1 голос
/ 30 декабря 2008

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

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

или это? : -)

0 голосов
/ 05 января 2011

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

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

совпадает с

print a[start : stop : step]

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

0 голосов
/ 05 января 2011

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

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

>>> A[4:1:-1]
[4, 3, 2]
0 голосов
/ 30 декабря 2008
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]
>>> 

Причина в том, что второй термин интерпретируется как «пока не индекс ==». Не указывать "пока индекс в диапазоне".

...