Erro na lista Python: [:: -1] passo em [: -1] fatia
pensei ter entendido o básico de cortar listas em python, mas tenho recebido um erro inesperado ao usar um passo negativo numa fatia, do seguinte modo:
>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-1:-1]
[]
(Note que isto está a ser executado no Python 3.5)
porque é que um passo[:-1:-1] reverso através da fatia a[:-1] da mesma maneira que faz através de toda a lista com um [: -1]?
Eu sei que podes usar a lista.reverse () as well, but trying to understanding the python slice funcionalidade melhor.5 answers
O primeiro -1
em {5]} não significa o que pensas que significa.
len(a)
). Isto acontece independentemente da direção da fatiagem.
Isto significa que
a[:-1:-1]
É equivalente a
a[:len(a)-1:-1]
Quando omitido durante a fatiagem inversa, o índice inicial é por omissão len(a)-1
, tornando o acima do equivalente a
a[len(a)-1:len(a)-1:-1]
Isto dá sempre uma lista vazia, uma vez que os índices de início e fim são os mesmos e o índice de fim é exclusivo.
Para cortar ao contrário até, e incluindo, o elemento zeroth pode usar qualquer uma das seguintes anotações:
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:None:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-len(a)-1:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Quando você digita [1, 2, 3, ...][1:4:1]
é o mesmo que [1, 2, 3, ...][slice(1, 4, 1)]
. Então 1:4:1
é a abreviatura do objeto slice
. slice
a Assinatura é slice(stop)
ou slice(start, stop[, step])
e também pode usar None
para argumentos.
:: -> slice(None, None, None)
:4 -> slice(4)
# and so on
Suponha que temos. as regras para os índices serão as seguintes:
- primeiro
c
é verificado. Default is+1
, sign ofc
indicates forward or backward direction of the step. O valor absoluto dec
indica o tamanho do degrau. - Than
a
is checked. Quandoc
é positivo ouNone
, por omissão paraa
é0
. Quandoc
é negativo, o valor por omissão paraa
é-1
. - finalmente
b
está verificado. Quandoc
é positivo ouNone
, por omissão parab
élen
. Quandoc
é o valor por omissão negativo parab
é-(len+1)
.
Nota 1 : as fatias degeneradas em Python são tratadas graciosamente:
- o índice demasiado grande ou demasiado pequeno é substituído por
len
ou0
. - um limite superior menor do que o limite inferior devolve uma lista ou um texto vazio ou qualquer outra coisa (para o Positivo
c
).
Nota 2 : em termos gerais, o Python apanha elementos enquanto esta condição (a < b) if (c > 0) else (a > b)
é True
(actualizando a += c
em cada passo). Além disso, todos os índices negativos são substituídos por len - index
.
Se combinar estas regras e notas fará sentido porque é que tem uma lista vazia. No seu caso:
In[1]: [1, 2, 3, 4, 5, 6][:-1:-1] # `c` is negative so `a` is -1 and `b` is -1
Out[1]: []
# it is the same as:
In[2]: [1, 2, 3, 4, 5, 6][-1: -1: -1] # which will produce you an empty list
Out[2]: []
Há uma boa discussão sobre a notação das fatias.: Explica a notação de fatia do Python!
Geralmente acho útil cortar um objecto range
(Isto só é possível em python3 - em python2 range
produz um list
e xrange
não pode ser cortado em fatias) se eu precisar de ver quais os índices que são usados para uma lista de um dado comprimento:
>>> range(10)[::-1]
range(9, -1, -1)
>>> range(10)[:-1]
range(0, 9)
E no seu último caso:
>>> range(10)[:-1:-1]
range(9, 9, -1)
Isto também explica o que aconteceu. O primeiro índice é 9, mas o 9 não é inferior ao índice de paragem 9 (note-se que em python o índice de paragem é excluído) por isso pára sem dar qualquer indicação elemento.
Note que a indexação também pode ser aplicada sequencialmente:
>>> list(range(10))[::-1][:-1] # first reverse then exclude last item.
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list(range(10))[:-1][::-1] # other way around
[8, 7, 6, 5, 4, 3, 2, 1, 0]
As fatias de Python parecem bastante simples no início, mas o seu comportamento é na verdade bastante complexo (as notas 3 e 5 são relevantes aqui). Se tiver uma fatia a[i:j:k]
:
- SE
i
ouj
forem negativos, referem-se a um índice a partir do fim dea
(por issoa[-1]
refere-se ao último elemento dea
) -
Se
i
ouj
não são especificados ou sãoNone
, eles padrão para as extremidades doa
, mas que termina depende do sinal dek
:- se
k
for positivo, estás a cortar para a frente, por issoi
torna-se 0 ej
torna-selen(a)
-
Se
k
for negativo, estás a cortar para trás, por issoi
torna-selen(a)
ej
torna-se o elemento antes do início dea
.NB::
j
não é possível ser substituído por-1, uma vez que fazer isso fará com que o Python tratej
como o último elemento dea
em vez do elemento (inexistente) antes dea[0]
. Obter o comportamento desejado, você deve usar-len(a)-1
(ou-(len(a)+1)
) no lugar dej
, o que significa que, para obtera[j]
, fatia começa com o último elemento dea
, vai para a esquerda paralen(a)
de elementos de e, em seguida, para a esquerda um elemento a mais, terminando antesa
for iniciado e, portanto, incluindoa[0]
na fatia.
- se
Portanto, a[:-1:-1]
significa " ir do fim de a
, que é a[-1]
(uma vez que {[2] } é indeterminado e {[11] } é negativo), para o último elemento de a
(desde j == -1
), com passo Tamanho de -1". i
e j
são iguais – você começa e pára de cortar no mesmo local – por isso a expressão avalia para uma lista vazia.
Para reverter a[:-1]
, pode usar a[-2::-1]
. Desta forma, a fatia começa no penúltimo elemento, a[-2]
(desde a[:-1]
não incluem a[-1]
) e vai para trás até que o elemento "antes" a[0]
, o que significa que a[0]
é incluído na fatia.
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[-2::-1]
[8, 7, 6, 5, 4, 3, 2, 1, 0]
slice
funciona de forma similar a range
na medida em que quando você faz do argumento de step
um número negativo, os argumentos de start
e stop
funcionam na direção oposta.
>>> list(range(9, -1, -1)) == a[::-1]
True
Alguns exemplos que podem ajudar a tornar isto mais claro:
>>> a[6:2:-2]
[6, 4]
>>> a[0:None:1] == a[::]
True
>>> a[-1:None:-1] == a[::-1]
True
>>> a[-2:None:-1] == a[:-1][::-1]
True