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.

Author: Matt Kelty, 2017-01-02

5 answers

O primeiro -1 em {5]} não significa o que pensas que significa.

Em fatiagem, os índices negativos de início / fim não são interpretados literalmente. Em vez disso, eles são usados para se referir convenientemente ao fim da lista (ou seja, eles são relativos a 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]
 22
Author: NPE, 2017-01-02 21:40:57

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:
  1. primeiro c é verificado. Default is +1, sign of c indicates forward or backward direction of the step. O valor absoluto de c indica o tamanho do degrau.
  2. Than a is checked. Quando c é positivo ou None, por omissão para a é 0. Quando c é negativo, o valor por omissão para a é -1.
  3. finalmente b está verificado. Quando c é positivo ou None, por omissão para b é len. Quando c é o valor por omissão negativo para b é -(len+1).

Nota 1 : as fatias degeneradas em Python são tratadas graciosamente:

  • o índice demasiado grande ou demasiado pequeno é substituído por len ou 0.
  • 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!
 6
Author: godaygo, 2017-05-23 11:47:25

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]
 4
Author: MSeifert, 2017-01-02 23:31:38

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 ou j forem negativos, referem-se a um índice a partir do fim de a (por isso a[-1] refere-se ao último elemento de a)
  • Se i ou j não são especificados ou são None, eles padrão para as extremidades do a, mas que termina depende do sinal de k:

    • se k for positivo, estás a cortar para a frente, por isso i torna-se 0 e j torna-se len(a)
    • Se k for negativo, estás a cortar para trás, por isso i torna-se len(a) e j torna-se o elemento antes do início de a.

      NB:: j não é possível ser substituído por-1, uma vez que fazer isso fará com que o Python trate j como o último elemento dea em vez do elemento (inexistente) antes de a[0]. Obter o comportamento desejado, você deve usar -len(a)-1 (ou -(len(a)+1)) no lugar de j, o que significa que, para obter a[j], fatia começa com o último elemento de a, vai para a esquerda para len(a) de elementos de e, em seguida, para a esquerda um elemento a mais, terminando antes a for iniciado e, portanto, incluindo a[0] na fatia.

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]
 1
Author: Josh, 2017-01-02 21:04:57

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
 1
Author: John B, 2017-01-03 02:47:14