Corte extendido que va al comienzo de la secuencia con zancada negativa

Ten paciencia conmigo mientras te explico mi pregunta. Salta al encabezado en negrita si ya entiendes la indexación de la lista de sectores extendida.

En Python, puedes indexar listas usando notación de segmento. Aquí hay un ejemplo:

>>> A = list(range(10)) >>> A[0:5] [0, 1, 2, 3, 4] 

También puede incluir una zancada, que actúa como un “paso”:

 >>> A[0:5:2] [0, 2, 4] 

También se permite que la zancada sea negativa, lo que significa que los elementos se recuperan en orden inverso:

 >>> A[5:0:-1] [5, 4, 3, 2, 1] 

¡Pero espera! Quería ver [4, 3, 2, 1, 0] . Oh, ya veo, necesito disminuir los índices de inicio y fin:

 >>> A[4:-1:-1] [] 

¿Que pasó? Está interpretando a -1 como al final de la matriz, no al principio. Sé que puedes lograr esto de la siguiente manera:

 >>> A[4::-1] [4, 3, 2, 1, 0] 

Pero no puedes usar esto en todos los casos. Por ejemplo, en un método que ha pasado índices.

Mi pregunta es:

¿Hay alguna buena forma pythonica de usar cortes extendidos con pasos negativos e índices de inicio y fin explícitos que incluyan el primer elemento de una secuencia?

Esto es lo que he encontrado hasta ahora, pero parece insatisfactorio.

 >>> A[0:5][::-1] [4, 3, 2, 1, 0] 

Es propenso a errores cambiar la semántica de start y stop . Use None o -(len(a) + 1) lugar de 0 o -1 . La semántica no es arbitraria. Vea el artículo de Edsger W. Dijkstra “Por qué la numeración debe comenzar en cero” .

 >>> a = range(10) >>> start, stop, step = 4, None, -1 

O

 >>> start, stop, step = 4, -(len(a) + 1), -1 >>> a[start:stop:step] [4, 3, 2, 1, 0] 

O

 >>> s = slice(start, stop, step) >>> a[s] [4, 3, 2, 1, 0] 

Cuando s es una secuencia, los índices negativos en s[i:j:k] se tratan especialmente :

Si i o j es negativo, el índice es relativo al final de la cadena: len(s) + i o len(s) + j se sustituye. Pero tenga en cuenta que -0 sigue siendo 0 .

es por eso que len(range(10)[4:-1:-1]) == 0 porque es equivalente a range(10)[4:9:-1] .

Ok, creo que esto es probablemente tan bueno como lo conseguiré. Gracias a Abgan por desatar la idea. Esto se basa en el hecho de que Ninguno en una porción se trata como si fuera un parámetro faltante. ¿Alguien tiene algo mejor?

 def getReversedList(aList, end, start, step): return aList[end:start if start!=-1 else None:step] 

edición: compruebe el start==-1 , no 0

Esto todavía no es lo ideal, porque estás dominando el comportamiento habitual de -1. Parece que el problema aquí son dos definiciones superpuestas de lo que se supone que sucederá. Quien gane se lleva las invocaciones válidas en busca de la otra intención.

 [ A[b] for b in range(end,start,stride) ] 

Más lento, sin embargo, puedes usar índices negativos, así que esto debería funcionar:

 [ A[b] for b in range(9, -1, -1) ] 

Me doy cuenta de que esto no es usar rebanadas, pero pensé que ofrecería la solución de todos modos si usar rebanadas específicamente para obtener el resultado no es una prioridad.

Creo que lo siguiente no te satisface:

 def getReversedList(aList, end, start, step): if step < 0 and start == 0: return aList[end::step] return aList[end:start:step] 

o lo hace? 🙂

Pero no puede usar eso si está almacenando sus índices en variables, por ejemplo.

¿Es esto satisfactorio?

 >>> a = range(10) >>> start = 0 >>> end = 4 >>> a[4:start-1 if start > 0 else None:-1] [4, 3, 2, 1, 0] 

Como usted dice, muy pocas personas entienden completamente todo lo que pueden hacer con el rebanado extendido, así que a menos que realmente necesite el rendimiento adicional, lo haría de la manera “obvia”:

rev_subset = reversed(data[start:stop])

 a[4::-1] 

Ejemplo:

 Python 2.6 (r26:66714, Dec 4 2008, 11:34:15) [GCC 4.0.1 (Apple Inc. build 5488)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> a = list(range(10)) >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> a[4:0:-1] [4, 3, 2, 1] >>> a[4::-1] [4, 3, 2, 1, 0] >>> 

La razón es que el segundo término se interpreta como “while no index ==”. Dejarlo fuera es “mientras que el índice está dentro del rango”.

Sé que esta es una vieja pregunta, pero en caso de que alguien como yo esté buscando respuestas:

 >>> A[5-1::-1] [4, 3, 2, 1, 0] >>> A[4:1:-1] [4, 3, 2] 

Puede utilizar un objeto de slice(start, stop, step) , que es tal que

 s=slice(start, stop, step) print a[s] 

es lo mismo que

 print a[start : stop : step] 

y, además, puede establecer cualquiera de los argumentos en None para indicar que no hay nada entre los dos puntos. Por lo tanto, en el caso de que otorgue, puede usar slice(4, None, -1) .