Являются ли возможности нарезки списка Python действительно асимметричными?

Рассмотрим следующий код:

>>> a = [0, 1, 2]
>>> for i in range(len(a)):
>>>   print a[0:i]

[]
[0]
[0, 1]

Однако, когда я переворачиваю код, чтобы взять фрагменты из другого конца списка, он больше не работает:

>>> for i in range(len(a)):
>>>   print a[-i:]

[0, 1, 2]
[2]
[1, 2]

Похоже, что единственный способ заставить второй кусок кода работать, это перевернуть список, сделать это первым способом и перевернуть каждый фрагмент перед его печатью. Есть лучший способ сделать это? Я иногда использую этот тип цикла и хотел бы, чтобы мой код был максимально чистым.

РЕДАКТИРОВАТЬ: В обоих циклах я итерации слева направо. Если я переключу направление итерации также для второго цикла, это сработает. Если я переключу направление итерации для первого цикла, он также будет иметь такой же сбой, что и второй цикл:

>>> for i in range(len(a)):
>>>   print a[i-1::-1]

[2, 1, 0]
[0]
[1, 0]

2 ответа

Первая итерация, вы нарезаете как -0что точно так же, как нарезка из 0, Только вторую итерацию вы нарезаете как -1, затем -2,

Возможно, вы могли бы использовать диапазон, начинающийся с отрицательного индекса:

for i in range(-len(a), 0):
    print a[-i:]

Обратное нарезание не может быть полностью симметричным в Python из-за индексации на основе 0. В частности, невозможно отличить -0 от 0. Но случай использования симметричного доступа в индексированных массивах на основе 0 будет диктовать, что если 0-й элемент сначала слева, то -0-й элемент (то есть отрицательный 0) является первым справа, но так как 0 и -0 являются одной и той же сущностью, это создает проблему.

Рассмотрим две ориентации индексов списка:

Вперед: первый элемент в позиции 0, второй элемент в позиции 1, ..., последний элемент в позиции n-1

Назад: первый элемент в позиции -1, второй в -2, ..., последний элемент в позиции -n

Следовательно, запись отрицательного индекса является сокращением для (length-index): collection[-i] == collection[len(collection) - i]

Или, рядом, индексация:

[0, 1, 2,...,n-1]
[-n,..., -3, -2, -1 ]

Где оба вышеуказанных индекса на самом деле идентичны.

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

оригинальный срез: a[0:i] == я элементы от левого конца (в 0) с размером шага 1 == a[0:i:1]

обратный срез: элементы i с правого конца (в -1) с размером шага -1.

Таким образом, правильный срез с другого конца будет a[-1:-1-i:-1]

Обратите внимание, что здесь значение остановки является отрицательным значением i, смещенным на -1 для учета -1-based-reversed-indexing, что необходимо, так как мы генерируем i, используя список на основе форвардов (например, функцию range.)

a = range(3) # [0,1,2]
for i in range(len(a)):
    # forward case, next to backward case
    print a[:i], a[-1:-1-i:-1]
# [] []
# [0] [2]
# [0, 1] [2, 1]
Другие вопросы по тегам