length - python string substring
Invertir una cadena en Python (23)
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.
¿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:
En Python, las cuerdas son inmutables . Cambiar una cadena no modifica la cadena. Crea uno nuevo.
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 que esto sea más legible y comprensible para alguien menos familiarizado con los cortes o la intención del autor original? Vamos a crear un objeto de división fuera de la notación de subíndice, asígnele un nombre descriptivo y pase a la notación de 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 sintaxis 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
Teóricamente mejor es recopilar 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 lleva 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 pitónico. ¡Buen trabajo!" Estoy tan perturbado que una comunidad tan brillante 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
- ver por ejemplo, ejemplo02
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 las matrices en otros lenguajes de programació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 entienden 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, existen 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
usando notación de corte
def rev_string(s):
return s[::-1]
usando la función invertida ()
def rev_string(s):
return ''''.join(reversed(s))
usando recursion
def rev_string(s):
if len(s) == 1:
return s
return s[-1] + rev_string(s[:-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
Aquí hay uno no lujoso:
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!")
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.
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 programació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)
El s[::-1]
de Paolo s[::-1]
es el más rápido; un enfoque más lento (quizás más legible, pero eso es discutible) es ''''.join(reversed(s))
.
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
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 = byterarray(''Reverse this!'', ''UTF-8'')
b.reverse()
b.decode(''UTF-8'')`
Producirá:
''!siht esreveR''
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
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
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
Otra alternativa (¡no es eficiente, solo para mostrar la diversidad de Python con tantas soluciones posibles!): Convierta la cadena a una lista usando la función list (). Un valor de lista es un tipo de datos mutable. Por lo tanto, podemos usar el método reverse () que invierte los objetos de una lista en su lugar. Y luego convertimos la lista de nuevo a una cadena usando el método de unión de lista con un separador vacío:
>>> s = ''hello world''
>>> s
''hello world''
>>> t = list(s) # convert to list
>>> t
[''h'', ''e'', ''l'', ''l'', ''o'', '' '', ''w'', ''o'', ''r'', ''l'', ''d'']
>>> t.reverse() # reverse method of list
>>> t
[''d'', ''l'', ''r'', ''o'', ''w'', '' '', ''o'', ''l'', ''l'', ''e'', ''h'']
>>> s = ''''.join(t) # convert to string
>>> s
''dlrow olleh''
Otra forma utilizando enumerar :
def reverse_string(string):
s = ''''
for i, char in enumerate(string[::-1]):
s +=char
return s
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)]
Qué tal si:
>>> ''hello world''[::-1]
''dlrow olleh''
Esta es la sintaxis 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.
Todas las soluciones anteriores son perfectas, pero si estamos tratando de revertir una cadena usando for loop en python se volverá un poco complicado, así es como 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.
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"
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.
def rev(str1):
print( str1[::-1])
str1="123"
r=rev(str1)
def reverse(input):
return reduce(lambda x,y : y+x, input)
s = ''hello''
ln = len(s)
i = 1
while True:
rev = s[ln-i]
print rev,
i = i + 1
if i == ln + 1 :
break
SALIDA:
o l l e h