Pregunta Invertir una cadena en Python


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

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


1069
2018-05-31 02:10


origen


Respuestas:


Qué tal si:

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

Esto es rebanada extendida sintaxis. Funciona haciendo [begin:end:step] - al dejar comenzar y finalizar y especificar un paso de -1, invierte una cadena.


2216
2018-05-31 02:11



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


217
2018-05-31 02:13



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

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

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

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

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

o para legibilidad y reutilización, ponga la rebanada en una función

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

y entonces:

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

Explicación más larga

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

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

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

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

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

    string[subscript]
    

El subíndice crea un corte al incluir dos puntos dentro de los corchetes:

    string[start:stop:step]

Para crear un corte fuera de los frenillos, deberá crear un objeto de corte:

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

Un enfoque legible:

Mientras ''.join(reversed('foo')) es legible, requiere llamar a un método de cadena, str.join, en otra función llamada, que puede ser bastante relativamente lenta. Pongamos esto en una función: volveremos a ello:

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

El enfoque más eficiente:

Mucho más rápido es usar una porción inversa:

'foo'[::-1]

Pero, ¿cómo podemos hacer que esto sea más legible y comprensible para alguien menos familiarizado con las rebanadas o la intención del autor original? Creemos un objeto de corte fuera de la notación de subíndice, asígnele un nombre descriptivo y páselo 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 realmente implementar esto como una función, creo que es semánticamente lo suficientemente claro como para simplemente usar un nombre descriptivo:

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

Y el uso es simple:

reversed_string('foo')

Lo que tu maestro probablemente quiera

Si tienes un instructor, es probable que quieran que comiences con una cadena vacía y construyas una cadena nueva a partir de la anterior. Puede hacerlo con sintaxis y literales puros utilizando un ciclo 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, recuerda, las cadenas son inmutables - Así que cada vez que parezca que estás agregando un personaje a tu new_string, teóricamente 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 es mejor recopilar sus subcadenas en una lista, y unirse a ellas más tarde:

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 tiempos 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 tiempos:

>>> 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 podría no:

... no confíe en la implementación eficiente de CPython de la concatenación de cadenas in situ para las sentencias 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 implementaciones que no usan refcounting. En las partes de la biblioteca sensibles al rendimiento, se debe usar el formulario '' .join () en su lugar. Esto asegurará que la concatenación ocurra en tiempo lineal a través de varias implementaciones.


168
2018-01-08 15:32



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é con la solución propuesta por Paolo, pero eso   tomó un asiento trasero al horror que sentí al leer la primera   comentar: "Eso es muy pitónico. ¡Buen trabajo!" Estoy tan perturbado que tal   una comunidad brillante piensa usar métodos tan crípticos para algo tan   básico es una buena idea. ¿Por qué no es solo a la inversa ()?

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

Trampas

  • El desarrollador puede esperar algo así como string.reverse()
  • El idiomático nativo (aka "aka"pitónico") la solución 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 sectores
  • El resultado de la notación de división puede ser contrario a la intuición en algunos casos:
    • ver, por ejemplo, example02
      • 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] puede echar a algunos desarrolladores

Razón fundamental

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

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

En términos simplificados, esto simplemente significa que cada carácter individual en una cadena se puede operar fácilmente como parte de una disposición secuencial de elementos, al igual que las matrices en otros lenguajes de programación.

Para comprender cómo funciona esto, revisar el ejemplo02 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

los carga cognitiva asociado a la comprensión de cómo funciona la notación de segmento en python puede ser demasiado para algunos adoptantes 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 lo contrario, existen enfoques alternativos, como funciones lambda, iteradores o declaraciones simples de funciones únicas.

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

Ver también


33
2017-10-31 22:24



Una forma menos desconcertante de mirarlo sería:

string = 'happy'
print(string)

'contento'

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

'yppah'

En inglés [-1 :: - 1] dice:

"Comenzando en -1, ve todo el camino, dando pasos de -1"


10
2018-04-01 07:49



Invierta una cadena en python sin usar reverse () o [:: - 1]

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

4
2017-12-10 12:57



def reverse(input):
    return reduce(lambda x,y : y+x, input)

3
2018-06-26 04:25



usando la notación rebanada

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

usando la función invertida ()

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

usando recursión

def rev_string(s): 
    if len(s) == 1:
        return s

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

3
2018-05-20 22:24



Aquí hay uno sin 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!")

2
2018-05-04 17:02