Error de la lista de Python:[::-1] paso en la porción
slice reverse (5)
Cuando escribe [1, 2, 3, ...][1:4:1]
es lo mismo que [1, 2, 3, ...][slice(1, 4, 1)]
. Entonces 1:4:1
es la abreviatura para el objeto de sector. slice
firma del slice
es slice(stop)
o slice(start, stop[, step])
y también puede usar None
para los argumentos.
:: -> slice(None, None, None)
:4 -> slice(4)
# and so on
Supongamos que tenemos [a: b: c]
. Las reglas para los índices serán las siguientes:
- La primera
c
está marcada. El valor predeterminado es+1
, el signo dec
indica la dirección hacia adelante o hacia atrás del paso. El valor absoluto dec
indica el tamaño del paso. - Que se comprueba una. Cuando
c
es positivo oNone
, el valor predeterminado paraa
es0
. Cuandoc
es negativo, el valor predeterminado paraa
es-1
. - Finalmente se comprueba
b
. Cuandoc
es positivo oNone
, el valor predeterminado parab
eslen
. Cuandoc
es negativo, el valor predeterminado parab
es-(len+1)
.
Nota 1 : Los cortes degenerados en Python se manejan con gracia:
- el índice que es demasiado grande o demasiado pequeño se reemplaza por
len
o0
. - un límite superior más pequeño que el límite inferior devuelve una lista o cadena vacía o cualquier otra cosa (para
c
positivo).
Nota 2 : En términos generales, Python recoge elementos mientras esta condición (a < b) if (c > 0) else (a > b)
es True
(se actualiza a += c
en cada paso). Además, todos los índices negativos se reemplazan con len - index
.
Si combina estas reglas y notas, tendrá sentido por qué recibió una lista vacía. En tu 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]: []
Hay una muy buena discusión acerca de la notación de división : ¡ Explique la notación de división de Python !
Pensé que entendía los conceptos básicos de la división de listas en python, pero he estado recibiendo un error inesperado al usar un paso negativo en una división, de la siguiente manera:
>>> 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]
[]
(Tenga en cuenta que esto se está ejecutando en Python 3.5)
¿Por qué un paso [: - 1: -1] a la inversa no recorre el corte a [: - 1] de la misma manera que lo hace a través de toda la lista con un [:: - 1]?
Me doy cuenta de que también puedes usar list.reverse (), pero tratar de comprender mejor la funcionalidad subyacente de la porción python.
Las rodajas de Python parecen bastante simples al principio, pero su comportamiento es bastante complejo (las notas 3 y 5 son relevantes aquí). Si tienes un sector a[i:j:k]
:
- Si
i
oj
son negativos, se refieren a un índice desde el final dea
(por lo quea[-1]
refiere al último elemento dea
) Si
i
oj
no están especificados, o sonNone
, se ubican por defecto en los extremos dea
, pero los extremos dependen del signo dek
:- si
k
es positivo, estás rebanando hacia delante, por lo quei
convierte en 0 yj
convierte enlen(a)
si
k
es negativo, estás rebanando hacia atrás, por lo quei
convierte enlen(a)
yj
convierte en el elemento antes del inicio dea
.NB:
j
no puede reemplazarse con -1, ya que al hacerlo, Python tratará aj
como el último elemento dea
elementoa
lugar del elemento (inexistente) antes dea[0]
. Para obtener el comportamiento deseado, debe usar-len(a)-1
(o-(len(a)+1)
) en lugar dej
, lo que significa que para obtenera[j]
, el sector comienza en el último elemento dea
, va a la izquierda para los elementoslen(a)
y luego deja un elemento más, termina antes dea
inicio y, por lo tanto, incluyea[0]
en la división.
- si
Por lo tanto, a[:-1:-1]
significa "ir desde el final de a
, que es a[-1]
(ya que i
no está especificado y k
es negativo), hasta el último elemento de a
(ya que j == -1
), con un tamaño de paso de -1 ". i
y j
son iguales: usted comienza y detiene el corte en el mismo lugar, por lo que la expresión se convierte en una lista vacía.
Para invertir a[:-1]
, puede usar a[-2::-1]
. De esta manera, la división comienza en el penúltimo elemento, a[-2]
(ya que a[:-1]
no incluye a[-1]
) y retrocede hasta que el elemento "antes" a[0]
, lo que significa que a[0]
está incluido en la rebanada.
>>> 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]
Por lo general, me parece útil cortar un objeto de range
(esto solo es posible en python3; en el range
python2 range
produce una list
y no se puede dividir el range
x) si necesito ver qué índices se usan para una lista de una longitud determinada:
>>> range(10)[::-1]
range(9, -1, -1)
>>> range(10)[:-1]
range(0, 9)
Y en tu último caso:
>>> range(10)[:-1:-1]
range(9, 9, -1)
Esto también explica lo que pasó. El primer índice es 9, pero 9 no es más bajo que el índice de parada 9 (tenga en cuenta que en python se excluye el índice de parada), por lo que se detiene sin dar ningún elemento.
Tenga en cuenta que la indexación también se puede aplicar secuencialmente:
>>> 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]
slice
funciona de manera similar al range
en el que al hacer que el argumento de step
un número negativo, los argumentos de start
y stop
funcionan en la dirección opuesta.
>>> list(range(9, -1, -1)) == a[::-1]
True
Algunos ejemplos que pueden ayudar a aclarar esto:
>>> 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
El primer -1
en a[:-1:-1]
no significa lo que crees que hace.
En el corte, los índices de inicio / fin negativos no se interpretan literalmente. En su lugar, se utilizan para referirse convenientemente al final de la lista (es decir, son relativos a len(a)
). Esto sucede independientemente de la dirección del corte.
Esto significa que
a[:-1:-1]
es equivalente a
a[:len(a)-1:-1]
Cuando se omite durante el corte inverso, el índice de inicio predeterminado es len(a)-1
, haciendo que el equivalente anterior sea
a[len(a)-1:len(a)-1:-1]
Esto siempre da una lista vacía, ya que los índices de inicio y fin son los mismos y el índice de finalización es exclusivo.
Para dividir en reversa hasta, e incluyendo, el elemento cero puede usar cualquiera de las siguientes notaciones:
>>> 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]