Являются ли возможности нарезки списка 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]