Rebanadas de zancada en reversa de Python

Un ejemplo específico de mi pregunta es: “¿Cómo puedo obtener ‘3210’ en este ejemplo?”

>>> foo = '0123456' >>> foo[0:4] '0123' >>> foo[::-1] '6543210' >>> foo[4:0:-1] # I was shooting for '3210' but made a fencepost error, that's fine, but... '4321' >>> foo[3:-1:-1] # How can I get '3210'? '' >>> foo[3:0:-1] '321' 

Parece extraño que pueda escribir foo [4: 0: -1], foo [5: 1: -1], etc. y obtener lo que esperaría, pero no hay forma de escribir la división para que aparezca ‘3210 ‘.

Una forma improvisada de hacer esto sería foo [0: 4] [:: – 1], pero esto crea dos objetos de cadena en el proceso. Realizaré esta operación literalmente miles de millones de veces, por lo que cada operación de cadena es costosa.

Debo estar perdiendo algo tonto y fácil. ¡Gracias por tu ayuda!

Simplemente excluya el índice de rango final …

 >>> foo[3::-1] '3210' 

Irónicamente, creo que no probaste la única opción.

Si está buscando algo un poco más legible para el ser humano que la notación de corte extendido:

 >>> foo = '0123456' >>> ''.join(reversed(foo[0:4])) '3210' 

Omita el índice final en su notación de división:

 >>> foo = '0123456' >>> foo[3::-1] '3210' 

Si tiene que hacer esto muchas veces, cree un objeto de sector que pueda usar una y otra vez

 >>> i = slice(3,None,-1) >>> foo[i] '3210' 

Después de leer la “documentación técnica” ( aquí ), específicamente la oración:

Si cualquiera de los límites es negativo, se le agrega la longitud de la secuencia.

Decidí probar esto, y funcionó:

 >>> foo = '0123456' >>> foo[3:-1-len(foo):-1] '3210' >>> 

Entonces, creo que la mejor respuesta para determinar mediante progtwigción el “punto final” sería proporcionar una función auxiliar bien nombrada que deje en claro que sus argumentos siempre se tratan como compensaciones positivas, tal vez special_slice()

Creo que la claridad de este caso ‘especial’ es extremadamente importante ya que muchos casos de uso comunes y significativos dependen del comportamiento predeterminado de las compensaciones negativas (es decir, agregarles la longitud). Personalmente, frecuentemente uso un punto final ‘-1’ para significar: parar justo antes del último elemento.

Entonces, basado en tu comentario:

… un algoritmo que funciona de la siguiente manera: foo [i: i-4: -1], comienza con una ‘i’ alta y baja.

Yo podría hacer lo siguiente:

 def slice_by_len(data, start, length, step=1): end = start + length if step > 0 else start - length if end < 0: # Fix the negative offset to get what we really want end -= len(data) return data[start:end:step] 

Y luego llámalo para cada rebanada requerida:

 foo_part = slice_by_len(foo, i, 4, -1) 

Lo anterior podría ir fácilmente en un bucle sobre los valores de 'i'

Puede usar s[::-1] para revertir la cadena completa. Pero si desea invertir cada subcadena con una longitud fija, primero puede extraer la subcadena y luego invertir la subcadena completa. Por ejemplo, supongamos que debemos comprobar si cada subcadena con longitud 3 de string foo es un palíndromo, podemos hacerlo de la siguiente manera:

 >>> foo = '0102030' >>> for i in range(len(foo)-3): ... if foo[i:i+3] == foo[i:i+3][::-1]: ... print(foo[i:i+3], 'is a palindrome') ... else: ... print(foo[i:i+3], 'is not a palindrome') ... 010 is a palindrome 102 is not a palindrome 020 is a palindrome 203 is not a palindrome 030 is a palindrome 

Si desea comprobar si una subcadena es un palíndromo como este:

 if foo[i:i+3] == foo[i+2:i-1:-1]: ... 

no podrá manejar el caso de que i sea 0 , ya que en realidad está comparando foo[0:3] con foo[2:-1:-1] , que es equivalente a foo[2:n-1:-1] , que a su vez es una cadena vacía.

El único inconveniente de la primera solución es que utiliza un poco más de memoria, pero no es gran cosa.

Además de las soluciones anteriores, puedes hacer algo como:

 foo = '0123456' foo[-4::-1] 

Supongo que si foo va a cambiar las longitudes, puede que esta no sea la mejor solución, pero si la longitud es estática, funcionaría.

Dado:

 >>> foo = '0123456' 

La cadena deseada 3210 es desde el 3er índice hasta los caracteres 0:

 >>> stop_idx=0 >>> start_idx=3 

Aquí hay dos soluciones genéricas:

  1. Tome el corte hacia adelante y luego inviértalo

     >>> foo[stop_idx:start_idx+1][::-1] '3210' 
  2. Basándose en esta respuesta , use un paso negativo y el elemento de detención 1 antes del primer elemento (más el desplazamiento de detención):

     >>> foo[start_idx:stop_idx-len(foo)-1:-1] '3210' >>> a[start_idx:stop_idx-len(a)-1:-1] [2, 1] 

Comparando los tiempos de ejecución, la primera versión es más rápida:

 >>> timeit.timeit('foo[stop_idx:start_idx+1][::-1]', setup='foo="012345"; stop_idx=0; start_idx=3', number=10_000_000) 1.7157553750148509 >>> timeit.timeit('foo[start_idx:stop_idx-len(foo)-1:-1]', setup='foo="012345"; stop_idx=0; start_idx=3', number=10_000_000) 1.9317215870250948 
 s="this is my world" pattern=re.findall(r'\S+',s) a=[] for i in range(len(pattern)): a.append((pattern[i][::-1])) print (a) print (" ".join(a))