Question Inverse une chaîne en Python


Il n'y a pas de construction reverse fonction pour Python str objet. Quelle est la meilleure façon de mettre en œuvre cette méthode?

Si vous fournissez une réponse très concise, veuillez préciser son efficacité. Par exemple, si le str l'objet est converti en un objet différent, etc.


1069
2018-05-31 02:10


origine


Réponses:


Que diriez-vous:

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

C'est tranche étendue syntaxe. Ça marche en faisant [begin:end:step] - en laissant commencer et terminer et en spécifiant un pas de -1, il inverse une chaîne.


2216
2018-05-31 02:11



@ Paolo s[::-1] est le plus rapide; une approche plus lente (peut-être plus lisible, mais c'est discutable) est ''.join(reversed(s)).


217
2018-05-31 02:13



Quelle est la meilleure façon d'implémenter une fonction inverse pour les chaînes?

Ma propre expérience avec cette question est académique. Cependant, si vous êtes un pro à la recherche de la réponse rapide, utilisez une tranche qui passe par -1:

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

ou plus lisible (mais plus lent en raison des recherches de nom de méthode et du fait que join forme une liste quand on lui donne un itérateur), str.join:

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

ou pour la lisibilité et la réutilisabilité, mettre la tranche dans une fonction

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

et alors:

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

Explication plus longue

Si vous êtes intéressé par l'exposition académique, continuez à lire.

Il n'y a pas de fonction inverse intégrée dans l'objet str de Python.

Voici quelques informations sur les chaînes de Python que vous devriez connaître:

  1. En Python, les chaînes sont immuables. Changer une chaîne ne modifie pas la chaîne. Il en crée un nouveau.

  2. Les cordes sont tranchantes. Trancher une chaîne vous donne une nouvelle chaîne d'un point de la chaîne, en avant ou en arrière, à un autre point, par incréments donnés. Ils prennent la notation de tranche ou un objet de tranche dans un indice:

    string[subscript]
    

L'indice crée une tranche en incluant un deux-points dans les accolades:

    string[start:stop:step]

Pour créer une découpe en dehors des accolades, vous devez créer un objet découpe:

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

Une approche lisible:

Tandis que ''.join(reversed('foo')) est lisible, il nécessite l'appel d'une méthode de chaîne, str.join, sur une autre fonction appelée, qui peut être plutôt relativement lente. Mettons ceci dans une fonction - nous y reviendrons:

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

L'approche la plus performante:

Beaucoup plus rapide utilise une tranche inverse:

'foo'[::-1]

Mais comment pouvons-nous rendre cela plus lisible et compréhensible pour quelqu'un qui connaît moins les tranches ou l'intention de l'auteur original? Créons un objet découpé en dehors de la notation de l'indice, lui donnons un nom descriptif et transmettons-le à la notation de l'indice.

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

Implémenter comme fonction

Pour réellement l'implémenter en tant que fonction, je pense qu'il est sémantiquement assez clair pour utiliser simplement un nom descriptif:

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

Et l'usage est simplement:

reversed_string('foo')

Ce que votre professeur veut probablement:

Si vous avez un instructeur, ils veulent probablement que vous commenciez avec une chaîne vide, et construisiez une nouvelle chaîne à partir de l'ancienne. Vous pouvez le faire avec de la syntaxe pure et des littéraux en utilisant une boucle 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

C'est théoriquement mauvais parce que, rappelez-vous, les chaînes sont immuables - Donc à chaque fois que vous ajoutez un personnage sur votre new_string, il est théoriquement en train de créer une nouvelle chaîne à chaque fois! Cependant, CPython sait comment l'optimiser dans certains cas, dont ce cas trivial en est un.

Meilleur entrainement

Théoriquement, mieux vaut rassembler vos sous-chaînes dans une liste, et les rejoindre plus tard:

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)

Cependant, comme nous le verrons dans les timings ci-dessous pour CPython, cela prend plus de temps car CPython peut optimiser la concaténation de chaîne.

Timings

Voici les horaires:

>>> 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 optimise la concaténation de chaînes, tandis que d'autres implémentations Peut-être pas:

... ne comptez pas sur l'implémentation efficace de CPython de concaténation de chaînes sur place pour les instructions de la forme a + = b ou a = a + b. Cette optimisation est fragile même dans CPython (elle ne fonctionne que pour certains types) et n'est pas présente du tout dans les implémentations qui n'utilisent pas refcounting. Dans les parties sensibles de la performance de la bibliothèque, le formulaire '' .join () doit être utilisé à la place. Cela assurera que la concaténation se produit en temps linéaire à travers différentes implémentations.


168
2018-01-08 15:32



Réponse rapide (TL; DR)

Exemple

### example01 -------------------
mystring  =   'coup_ate_grouping'
backwards =   mystring[::-1]
print backwards

### ... or even ...
mystring  =   'coup_ate_grouping'[::-1]
print mystring

### result01 -------------------
'''
gnipuorg_eta_puoc
'''

Réponse détaillée

Contexte

Cette réponse est fournie pour répondre à la préoccupation suivante de @odigity:

Sensationnel. J'ai d'abord été horrifié par la solution proposée par Paolo, mais   a pris un siège arrière à l'horreur que je me suis senti en lisant le premier   commentaire: "C'est très pythonique, bon travail!" Je suis tellement perturbé que   une communauté brillante pense à l'aide de ces méthodes cryptiques pour quelque chose de si   basic est une bonne idée. Pourquoi n'est-ce pas juste s.reverse ()?

Problème

  • Le contexte
    • Python 2.x
    • Python 3.x
  • Scénario:
    • Le développeur veut transformer une chaîne
    • La transformation consiste à inverser l'ordre de tous les personnages

Solution

Pièges

  • Le développeur peut s'attendre à quelque chose comme string.reverse()
  • L'idiomatique natif (aka "pythonique") la solution peut ne pas être lisible pour les développeurs plus récents
  • Le développeur peut être tenté d'implémenter sa propre version de string.reverse() pour éviter la notation de tranche.
  • La sortie de la notation de tranche peut être contre-intuitive dans certains cas:
    • voir, par exemple, l'exemple 02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • par rapport à
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • par rapport à
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • les différents résultats de l'indexation sur [-1] peut jeter certains développeurs

Raisonnement

Python a une circonstance particulière à connaître: une chaîne est un itérable type.

Une raison d'exclure un string.reverse() La méthode consiste à inciter les développeurs de Python à exploiter la puissance de cette circonstance particulière.

En termes simplifiés, cela signifie simplement que chaque caractère d'une chaîne peut être facilement exploité dans le cadre d'un arrangement séquentiel d'éléments, tout comme les tableaux dans d'autres langages de programmation.

Pour comprendre comment cela fonctionne, l'examen de l'exemple 02 peut fournir un bon aperçu.

Exemple02

### 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'

Conclusion

le charge cognitive Associé à la compréhension de la façon dont la notation en tranches fonctionne en python peut en effet être trop pour certains adoptants et développeurs qui ne souhaitent pas investir beaucoup de temps dans l'apprentissage de la langue.

Néanmoins, une fois les principes de base compris, la puissance de cette approche par rapport aux méthodes de manipulation de chaînes fixes peut être très favorable.

Pour ceux qui pensent autrement, il existe des approches alternatives, telles que les fonctions lambda, les itérateurs ou les déclarations de fonctions uniques.

Si vous le souhaitez, un développeur peut implémenter sa propre méthode string.reverse (), mais il est bon de comprendre la logique derrière cet aspect de python.

Voir également


33
2017-10-31 22:24



Une façon moins perplexe de le regarder serait:

string = 'happy'
print(string)

'content'

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

'yppah'

En anglais [-1 :: - 1] se lit comme suit:

"A partir de -1, aller tout le chemin, en prenant des mesures de -1"


10
2018-04-01 07:49



Inverse une chaîne en python sans utiliser reverse () ou [:: - 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



en utilisant la notation de tranche

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

en utilisant la fonction reverse ()

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

en utilisant la récursivité

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

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

3
2018-05-20 22:24