Invertir una cadena en Python

No hay reverse función reverse incorporada para el objeto str de Python. ¿Cuál es la mejor manera de implementar este método?

Si proporciona una respuesta muy concisa, por favor explique su eficiencia. Por ejemplo, si el objeto str se convierte en un objeto diferente, etc.

Qué tal si:

 >>> 'hello world'[::-1] 'dlrow olleh' 

Esta es la syntax de la porción extendida . Funciona al hacer [begin:end:step] ; al dejar begin y end y especificando un paso de -1, invierte una cadena.

El s[::-1] @Paolo es el más rápido; un enfoque más lento (tal vez más legible, pero eso es discutible) es ''.join(reversed(s)) .

¿Cuál es la mejor manera de implementar una función inversa para cadenas?

Mi propia experiencia con esta pregunta es académica. Sin embargo, si eres un profesional en busca de la respuesta rápida, usa una porción que paso por -1 :

 >>> 'a string'[::-1] 'gnirts a' 

o más legible (pero más lento debido a las búsquedas de nombres de métodos y al hecho de que unirse forma una lista cuando se le asigna un iterador), str.join :

 >>> ''.join(reversed('a string')) 'gnirts a' 

o para facilitar la lectura y la reutilización, ponga la división en una función

 def reversed_string(a_string): return a_string[::-1] 

y entonces:

 >>> reversed_string('a_string') 'gnirts_a' 

Explicacion mas larga

Si estás interesado en la exposición académica, sigue leyendo.

No hay una función inversa incorporada en el objeto str de Python.

Aquí hay un par de cosas sobre las cuerdas de Python que debes saber:

  1. En Python, las cuerdas son inmutables . Cambiar una cadena no modifica la cadena. Crea uno nuevo.

  2. Las cuerdas son rebanables. Cortar una cadena te da una nueva cadena desde un punto de la cadena, hacia atrás o hacia adelante, a otro punto, en incrementos dados. Toman notación de división o un objeto de división en un subíndice:

     string[subscript] 

El subíndice crea una porción al incluir dos puntos dentro de las llaves:

  string[start:stop:step] 

Para crear una división fuera de las llaves, deberá crear un objeto de división:

  slice_obj = slice(start, stop, step) string[slice_obj] 

Un enfoque legible:

Mientras que ''.join(reversed('foo')) es legible, requiere llamar a un método de cadena, str.join , en otra función llamada, que puede ser relativamente lenta. Vamos a poner esto en una función, vamos a volver a ella:

 def reverse_string_readable_answer(string): return ''.join(reversed(string)) 

El enfoque más performante:

Mucho más rápido es usar un corte inverso:

 'foo'[::-1] 

Pero, ¿cómo podemos hacer esto más legible y comprensible para alguien menos familiarizado con los cortes o con la intención del autor original? Vamos a crear un objeto de sector fuera de la notación del subíndice, asígnele un nombre descriptivo y pase a la notación del subíndice.

 start = stop = None step = -1 reverse_slice = slice(start, stop, step) 'foo'[reverse_slice] 

Implementar como Función

Para implementar esto como una función, creo que es semánticamente lo suficientemente claro como para usar simplemente un nombre descriptivo:

 def reversed_string(a_string): return a_string[::-1] 

Y el uso es simplemente:

 reversed_string('foo') 

Lo que tu profesor probablemente quiere:

Si tiene un instructor, es probable que quieran comenzar con una cadena vacía y construir una nueva cadena a partir de la anterior. Puedes hacer esto con syntax pura y literales usando un bucle while:

 def reverse_a_string_slowly(a_string): new_string = '' index = len(a_string) while index: index -= 1 # index = index - 1 new_string += a_string[index] # new_string = new_string + character return new_string 

Esto es teóricamente malo porque, recuerde, las cadenas son inmutables , por lo que cada vez que parece que está agregando un carácter a su nueva cadena, ¡en teoría está creando una nueva cadena cada vez! Sin embargo, CPython sabe cómo optimizar esto en ciertos casos, de los cuales este caso trivial es uno.

Mejores prácticas

En teoría, mejor es recostackr las subcadenas en una lista y unirlas más adelante:

 def reverse_a_string_more_slowly(a_string): new_strings = [] index = len(a_string) while index: index -= 1 new_strings.append(a_string[index]) return ''.join(new_strings) 

Sin embargo, como veremos en los horarios a continuación para CPython, esto en realidad toma más tiempo, porque CPython puede optimizar la concatenación de cadenas.

Tiempos

Aquí están los horarios:

 >>> a_string = 'amanaplanacanalpanama' * 10 >>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string))) 10.38789987564087 >>> min(timeit.repeat(lambda: reversed_string(a_string))) 0.6622700691223145 >>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string))) 25.756799936294556 >>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string))) 38.73570013046265 

CPython optimiza la concatenación de cadenas, mientras que otras implementaciones pueden no :

… no confíe en la implementación eficiente de CPython de la concatenación de cadenas en el lugar para las declaraciones en la forma a + = b o a = a + b. Esta optimización es frágil incluso en CPython (solo funciona para algunos tipos) y no está presente en absoluto en implementaciones que no usan refcounting. En las partes de la biblioteca sensibles al rendimiento, se debe utilizar el formulario ” .join () en su lugar. Esto asegurará que la concatenación ocurra en tiempo lineal en varias implementaciones.

Respuesta rápida (TL; DR)

Ejemplo

 ### example01 ------------------- mystring = 'coup_ate_grouping' backwards = mystring[::-1] print backwards ### ... or even ... mystring = 'coup_ate_grouping'[::-1] print mystring ### result01 ------------------- ''' gnipuorg_eta_puoc ''' 

Respuesta detallada

Fondo

Esta respuesta se proporciona para abordar la siguiente inquietud de @odigity:

Guau. Al principio me horroricé por la solución que propuso Paolo, pero eso me hizo retroceder ante el horror que sentí al leer el primer comentario: “Eso es muy pythonico. ¡Buen trabajo!” Estoy tan perturbado que una comunidad tan shiny cree que usar métodos tan crípticos para algo tan básico es una buena idea. ¿Por qué no es sólo en el reverso ()?

Problema

  • Contexto
    • Python 2.x
    • Python 3.x
  • Guión:
    • El desarrollador quiere transformar una cadena
    • La transformación es invertir el orden de todos los personajes.

Solución

  • example01 produce el resultado deseado, utilizando notación de sector extendida .

Escollos

  • El desarrollador podría esperar algo como string.reverse()
  • La solución idiomática nativa (también conocida como ” pythonic “) puede no ser legible para los desarrolladores más nuevos
  • El desarrollador puede tener la tentación de implementar su propia versión de string.reverse() para evitar la notación de segmento.
  • La salida de notación de segmento puede ser contraintuitiva en algunos casos:
    • ver por ejemplo, ejemplo02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • comparado con
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • comparado con
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • Los diferentes resultados de la indexación en [-1] pueden echar a algunos desarrolladores

Razón fundamental

Python tiene una circunstancia especial a tener en cuenta: una cadena es un tipo iterable .

Una razón para excluir un método string.reverse() es dar a los desarrolladores de Python incentivos para aprovechar el poder de esta circunstancia especial.

En términos simplificados, esto simplemente significa que cada carácter individual en una cadena puede operarse fácilmente como parte de una disposición secuencial de elementos, al igual que los arreglos en otros lenguajes de progtwigción.

Para entender cómo funciona esto, revisar example02 puede proporcionar una buena visión general.

Ejemplo02

 ### example02 ------------------- ## start (with positive integers) print 'coup_ate_grouping'[0] ## => 'c' print 'coup_ate_grouping'[1] ## => 'o' print 'coup_ate_grouping'[2] ## => 'u' ## start (with negative integers) print 'coup_ate_grouping'[-1] ## => 'g' print 'coup_ate_grouping'[-2] ## => 'n' print 'coup_ate_grouping'[-3] ## => 'i' ## start:end print 'coup_ate_grouping'[0:4] ## => 'coup' print 'coup_ate_grouping'[4:8] ## => '_ate' print 'coup_ate_grouping'[8:12] ## => '_gro' ## start:end print 'coup_ate_grouping'[-4:] ## => 'ping' (counter-intuitive) print 'coup_ate_grouping'[-4:-1] ## => 'pin' print 'coup_ate_grouping'[-4:-2] ## => 'pi' print 'coup_ate_grouping'[-4:-3] ## => 'p' print 'coup_ate_grouping'[-4:-4] ## => '' print 'coup_ate_grouping'[0:-1] ## => 'coup_ate_groupin' print 'coup_ate_grouping'[0:] ## => 'coup_ate_grouping' (counter-intuitive) ## start:end:step (or start:end:stride) print 'coup_ate_grouping'[-1::1] ## => 'g' print 'coup_ate_grouping'[-1::-1] ## => 'gnipuorg_eta_puoc' ## combinations print 'coup_ate_grouping'[-1::-1][-4:] ## => 'puoc' 

Conclusión

La carga cognitiva asociada con la comprensión de cómo funciona la notación de corte en Python puede ser demasiado para algunos adoptadores y desarrolladores que no desean invertir mucho tiempo en aprender el idioma.

Sin embargo, una vez que se comprenden los principios básicos, el poder de este enfoque sobre los métodos de manipulación de cadenas fijas puede ser bastante favorable.

Para aquellos que piensan de otra manera, hay enfoques alternativos, como las funciones lambda, los iteradores o las declaraciones de funciones únicas simples.

Si lo desea, un desarrollador puede implementar su propio método string.reverse (), sin embargo, es bueno entender la razón detrás de este aspecto de python.

Ver también

  • enfoque simple alternativo
  • enfoque simple alternativo
  • explicación alternativa de notación de corte

Una manera menos perpleja de verlo sería:

 string = 'happy' print(string) 

‘feliz’

 string_reversed = string[-1::-1] print(string_reversed) 

‘yppah’

En inglés [-1 :: – 1] se lee como:

“Comenzando en -1, sigue todo el camino, tomando pasos de -1”

1. usando notación de corte

 def rev_string(s): return s[::-1] 

2. usando la función invertida ()

 def rev_string(s): return ''.join(reversed(s)) 

3. usando la recursion

 def rev_string(s): if len(s) == 1: return s return s[-1] + rev_string(s[:-1]) 

Invierta una cadena en python sin usar reversed () o [:: – 1]

 def reverse(test): n = len(test) x="" for i in range(n-1,-1,-1): x += test[i] return x 

Esta es también una forma interesante:

 def reverse_words_1(s): rev = '' for i in range(len(s)): j = ~i # equivalent to j = -(i + 1) rev += s[j] return rev 

o similar:

 def reverse_words_2(s): rev = '' for i in reversed(range(len(s)): rev += s[i] return rev 

Otra forma más ‘exótica’ usando byterarray que soporta .reverse ()

 b = bytearray('Reverse this!', 'UTF-8') b.reverse() b.decode('UTF-8') 

Producirá:

 '!siht esreveR' 
 def reverse(input): return reduce(lambda x,y : y+x, input) 
 original = "string" rev_index = original[::-1] rev_func = list(reversed(list(original))) #nsfw print(original) print(rev_index) print(''.join(rev_func)) 

Aquí hay un no de fantasía:

 def reverse(text): r_text = '' index = len(text) - 1 while index >= 0: r_text += text[index] #string canbe concatenated index -= 1 return r_text print reverse("hello, world!") 

Método recursivo:

 def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1]) 

ejemplo:

 print(reverse("Hello!")) #!olleH 

Todas las soluciones anteriores son perfectas, pero si estamos intentando revertir una cadena usando for loop en python se volverá un poco complicado, así que aquí es cómo podemos revertir una cadena usando for loop

 string ="hello,world" for i in range(-1,-len(string)-1,-1): print (string[i],end=(" ")) 

Espero que este sea de ayuda para alguien.

Esa es mi manera:

 def reverse_string(string): character_list = [] for char in string: character_list.append(char) reversed_string = "" for char in reversed(character_list): reversed_string += char return reversed_string 

Aquí hay uno sin [::-1] o reversed (para fines de aprendizaje):

 def reverse(text): new_string = [] n = len(text) while (n > 0): new_string.append(text[n-1]) n -= 1 return ''.join(new_string) print reverse("abcd") 

puede usar += para concatenar cadenas, pero join() es más rápido.

 def reverse_string(string): length = len(string) temp = '' for i in range(length): temp += string[length - i - 1] return temp print(reverse_string('foo')) #prints "oof" 

Esto funciona en bucle a través de una cadena y asignando sus valores en orden inverso a otra cadena.

Invierta una cuerda sin magia de python.

 >>> def reversest(st): a=len(st)-1 for i in st: print(st[a],end="") a=a-1 

Aquí está simplemente:

Imprimir “loremipsum” [- 1 :: – 1]

y algunos lógicamente:

 def str_reverse_fun(): empty_list = [] new_str = 'loremipsum' index = len(new_str) while index: index = index - 1 empty_list.append(new_str[index]) return ''.join(empty_list) print str_reverse_fun() 

salida:

muspimerol

Esta es una función inversa simple y significativa, fácil de entender y codificar

 def reverse_sentence(text): words = text.split(" ") reverse ="" for word in reversed(words): reverse += word+ " " return reverse 

s = ‘Hola mundo’

s [:: – 1]

en el ejemplo anterior, la etiqueta s o la variable s contiene una cadena que contiene la cadena Hello world y, en el segundo paso, imprimo el reverso de la cadena Hello world al comenzar desde todo a todo en el orden de paso inverso con -1.

Claro, en Python puedes hacer cosas muy elegantes de 1 línea. 🙂
Aquí hay una solución simple y completa que podría funcionar en cualquier lenguaje de progtwigción.

 def reverse_string(phrase): reversed = "" length = len(phrase) for i in range(length): reversed += phrase[length-1-i] return reversed phrase = raw_input("Provide a string: ") print reverse_string(phrase) 
 s = 'hello' ln = len(s) i = 1 while True: rev = s[ln-i] print rev, i = i + 1 if i == ln + 1 : break 

SALIDA:

 olleh 

Puede utilizar la función invertida con una lista comprehesive. Pero no entiendo por qué este método fue eliminado en Python 3, fue innecesariamente.

 string = [ char for char in reversed(string)]