Een string omkeren in Python

Er is geen ingebouwde reverse-functie voor het str-object van Python. Wat is de beste manier om deze methode te implementeren?

Als u een zeer beknopt antwoord geeft, geef dan een toelichting op de efficiëntie ervan. Bijvoorbeeld of het object strwordt geconverteerd naar een ander object, enz.


Antwoord 1, autoriteit 100%

Wat dacht je van:

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

Dit is uitgebreide segment-syntaxis. Het werkt door [begin:end:step]uit te voeren – door begin en einde uit te laten en een stap van -1 op te geven, wordt een string omgekeerd.


Antwoord 2, autoriteit 10%

@Paolo’s s[::-1]is het snelst; een langzamere aanpak (misschien leesbaarder, maar dat is discutabel) is ''.join(reversed(s)).


Antwoord 3, autoriteit 9%

Wat is de beste manier om een reverse-functie voor strings te implementeren?

Mijn eigen ervaring met deze vraag is academisch. Als je echter een professional bent die op zoek is naar het snelle antwoord, gebruik dan een segment dat stapsgewijs -1:

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

of leesbaarder (maar langzamer vanwege de methodenaam-lookups en het feit dat join een lijst vormt wanneer een iterator wordt gegeven), str.join:

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

of voor leesbaarheid en herbruikbaarheid, plaats de slice in een functie

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

en dan:

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

Langere uitleg

Als je geïnteresseerd bent in de academische expositie, lees dan verder.

Er is geen ingebouwde reverse-functie in het str-object van Python.

Hier zijn een paar dingen over de strings van Python die je moet weten:

  1. In Python zijn strings onveranderlijk. Het wijzigen van een string verandert de string niet. Er wordt een nieuwe gemaakt.

  2. Tekenreeksen zijn segmenteerbaar. Als u een string doorsnijdt, krijgt u een nieuwe string van het ene punt in de string, achteruit of vooruit, naar een ander punt, met bepaalde stappen. Ze gebruiken plaknotatie of een plakobject in een subscript:

    string[subscript]
    

Het subscript maakt een segment door een dubbele punt tussen de accolades op te nemen:

   string[start:stop:step]

Als u een segment buiten de accolades wilt maken, moet u een segmentobject maken:

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

Een leesbare aanpak:

Hoewel ''.join(reversed('foo'))leesbaar is, vereist het het aanroepen van een stringmethode, str.join, op een andere aangeroepen functie, die kan nogal relatief traag zijn. Laten we dit in een functie stoppen – we komen er op terug:

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

Meest presterende aanpak:

Veel sneller gebruikt een omgekeerde slice:

'foo'[::-1]

Maar hoe kunnen we dit meer leesbaar en begrijpelijker maken voor iemand die minder bekend is met plakjes of de intentie van de originele auteur? Laten we een slice-object maken buiten de subscript-notatie, geef het een beschrijvende naam en geef deze door aan de subscript-notatie.

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

Implementeren als functie

Om dit daadwerkelijk als een functie te implementeren, denk ik dat het semantisch duidelijk genoeg is om eenvoudig een beschrijvende naam te gebruiken:

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

en gebruik is eenvoudig:

reversed_string('foo')

Wat uw leraar waarschijnlijk wil:

Als u een instructeur heeft, willen ze waarschijnlijk dat u begint met een lege snaar en een nieuwe snaar van de oude op te bouwen. Je kunt dit doen met pure syntaxis en literalen met behulp van een tijdje lus:

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

Dit is theoretisch slecht omdat, onthoud, strings zijn onveranderlijk– dus elke keer dat het lijkt alsof je een teken toevoegt aan je new_string, creëert het theoretisch een elke keer nieuwe snaar! CPython weet dit echter in bepaalde gevallen te optimaliseren, waarvan dit triviale geval er één is.

Beste werkwijze

Theoretisch is het beter om je substrings in een lijst te verzamelen en ze later samen te voegen:

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)

Zoals we in de onderstaande timings voor CPython zullen zien, duurt dit echter langer, omdat CPython de aaneenschakeling van strings kan optimaliseren.

Timingen

Dit zijn de tijden:

>>> 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 optimaliseert de samenvoeging van tekenreeksen, terwijl andere implementaties misschien niet:

… vertrouw niet op de efficiënte implementatie van CPYPERTHON van in-peilige string-aaneenvoeging voor uitspraken in het formulier A + = B of A = A + B. Deze optimalisatie is fragiel, zelfs in CPYTHON (het werkt alleen voor sommige typen) en is helemaal niet aanwezig in implementaties die geen RefCrage gebruiken. In prestatiegevoelige delen van de bibliotheek moet in plaats daarvan het formulier ” .join () worden gebruikt. Dit zorgt ervoor dat aaneenschakeling plaatsvindt in lineaire tijd in verschillende implementaties.


Antwoord 4

Snel antwoord (TL; DR)

Voorbeeld

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

Gedetailleerd antwoord

Achtergrond

Dit antwoord is verstrekt om de volgende zorg van @odigity aan te pakken:

WOW. Ik was in eerste instantie geschokt door de oplossing Paolo voorgesteld, maar dat
nam een ​​achterbank naar de gruwel die ik vond bij het lezen van de eerste
Commentaar: “Dat is erg pythonic, goed werk!” Ik ben zo gestoord dat dat
Een heldere gemeenschap vindt het gebruik van dergelijke cryptische methoden voor iets dus
Basic is een goed idee. Waarom is het niet gewoon S.Reverse ()?

Probleem

  • context
    • python 2.x
    • python 3.x
  • scenario:
    • ontwikkelaar wil een string transformeren
    • Transformatie is om de volgorde van alle personages achteruit te zetten

Oplossing

valkuilen

  • Developer kan iets verwachten als string.reverse()
  • de inheemse idiomatische (aka “Pythonic “) is mogelijk niet leesbaar voor nieuwere ontwikkelaars
  • Developer kan in de verleiding komen om zijn of haar eigen versie van string.reverse()te implementeren om slice-notatie te voorkomen.
  • De output van slice-notatie kan in sommige gevallen tegen intuïtief zijn:
    • Zie b.v. example02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • in vergelijking met
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • in vergelijking met
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • De verschillende uitkomsten van indexering op [-1]kunnen sommige ontwikkelaars uitschakelen

RATIONALE

Python heeft een speciale omstandigheid om op de hoogte te zijn van: een string is een Itable Type.

Eén reden voor het uitsluiten van een string.reverse()methode is om Python-ontwikkelaars incentive te geven om de kracht van deze speciale omstandigheid te benutten.

In vereenvoudigde termen betekent dit eenvoudig dat elk individueel teken in een string eenvoudig kan worden gebruikt als onderdeel van een sequentiële regeling van elementen, net als arrays in andere programmeertalen.

Om te begrijpen hoe dit werkt, kan het beoordelen van exemplaar02 een goed overzicht bieden.

Voorbeeld02

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

CONCLUSIE

De cognitieve lading geassocieerd met het begrijpen hoe slice notatie werkt in Python inderdaad te veel voor Sommige adoptanten en ontwikkelaars die niet veel tijd willen investeren in het leren van de taal.

Niettemin, zodra de basisprincipes worden begrepen, kan de kracht van deze aanpak over vaste stringmanipulatiemethoden behoorlijk gunstig zijn.

Voor degenen die anders denken, zijn er alternatieve benaderingen, zoals Lambda-functies, iterators of eenvoudige eenmalige functieverklaringen.

Indien gewenst, kan een ontwikkelaar haar eigen string implementeren. Reverse () -methode, maar het is goed om de redenering achter dit aspect van Python te begrijpen.

Zie ook


Antwoord 5

Dit antwoord is iets langer en bevat 3 secties: benchmarks van bestaande oplossingen, Waarom de meeste oplossingen hier zijn verkeerd , mijn oplossing .

De bestaande antwoorden zijn alleen correct als Unicode-modificatoren / grafmachtige clusters worden genegeerd. Ik zal daar later mee omgaan, maar eerst eens kijken naar de snelheid van sommige erkeringsalgoritmen:

list_comprehension  : min:   0.6μs, mean:   0.6μs, max:    2.2μs
reverse_func        : min:   1.9μs, mean:   2.0μs, max:    7.9μs
reverse_reduce      : min:   5.7μs, mean:   5.9μs, max:   10.2μs
reverse_loop        : min:   3.0μs, mean:   3.1μs, max:    6.8μs

list_comprehension  : min:   4.2μs, mean:   4.5μs, max:   31.7μs
reverse_func        : min:  75.4μs, mean:  76.6μs, max:  109.5μs
reverse_reduce      : min: 749.2μs, mean: 882.4μs, max: 2310.4μs
reverse_loop        : min: 469.7μs, mean: 577.2μs, max: 1227.6μs

Je kunt zien dat de tijd voor het begrijpen van de lijst (reversed = string[::-1]) in alle gevallen verreweg het laagst is (zelfs na het corrigeren van mijn typfout).

Tekenreeksomkering

Als je een string echt op een normale manier wilt omkeren, is het VEEL ingewikkelder. Neem bijvoorbeeld de volgende tekenreeks (bruine vinger die naar links wijst, gele vinger omhoog). Dat zijn twee grafemen, maar 3 Unicode-codepunten. De extra is een skin modifier.

example = "👈🏾👆"

Maar als je het omkeert met een van de gegeven methoden, krijg je bruine vinger naar boven, gele vinger naar links. De reden hiervoor is dat de “bruine” kleurmodifier zich nog steeds in het midden bevindt en wordt toegepast op alles ervoor. Dus we hebben

  • U: vinger omhoog
  • M: bruine modifier
  • L: vinger naar links

en

original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)

Unicode Grapheme-clusterszijn iets ingewikkelder dan alleen modificatiecodepunten. Gelukkig is er een bibliotheek voor het verwerken van graphemes:

>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']

en daarom zou het juiste antwoord zijn

def reverse_graphemes(string):
    g = list(grapheme.graphemes(string))
    return ''.join(g[::-1])

die ook verreweg de langzaamste is:

list_comprehension  : min:    0.5μs, mean:    0.5μs, max:    2.1μs
reverse_func        : min:   68.9μs, mean:   70.3μs, max:  111.4μs
reverse_reduce      : min:  742.7μs, mean:  810.1μs, max: 1821.9μs
reverse_loop        : min:  513.7μs, mean:  552.6μs, max: 1125.8μs
reverse_graphemes   : min: 3882.4μs, mean: 4130.9μs, max: 6416.2μs

De code

#!/usr/bin/env python
import numpy as np
import random
import timeit
from functools import reduce
random.seed(0)
def main():
    longstring = ''.join(random.choices("ABCDEFGHIJKLM", k=2000))
    functions = [(list_comprehension, 'list_comprehension', longstring),
                 (reverse_func, 'reverse_func', longstring),
                 (reverse_reduce, 'reverse_reduce', longstring),
                 (reverse_loop, 'reverse_loop', longstring)
                 ]
    duration_list = {}
    for func, name, params in functions:
        durations = timeit.repeat(lambda: func(params), repeat=100, number=3)
        duration_list[name] = list(np.array(durations) * 1000)
        print('{func:<20}: '
              'min: {min:5.1f}μs, mean: {mean:5.1f}μs, max: {max:6.1f}μs'
              .format(func=name,
                      min=min(durations) * 10**6,
                      mean=np.mean(durations) * 10**6,
                      max=max(durations) * 10**6,
                      ))
        create_boxplot('Reversing a string of length {}'.format(len(longstring)),
                       duration_list)
def list_comprehension(string):
    return string[::-1]
def reverse_func(string):
    return ''.join(reversed(string))
def reverse_reduce(string):
    return reduce(lambda x, y: y + x, string)
def reverse_loop(string):
    reversed_str = ""
    for i in string:
        reversed_str = i + reversed_str
    return reversed_str
def create_boxplot(title, duration_list, showfliers=False):
    import seaborn as sns
    import matplotlib.pyplot as plt
    import operator
    plt.figure(num=None, figsize=(8, 4), dpi=300,
               facecolor='w', edgecolor='k')
    sns.set(style="whitegrid")
    sorted_keys, sorted_vals = zip(*sorted(duration_list.items(),
                                           key=operator.itemgetter(1)))
    flierprops = dict(markerfacecolor='0.75', markersize=1,
                      linestyle='none')
    ax = sns.boxplot(data=sorted_vals, width=.3, orient='h',
                     flierprops=flierprops,
                     showfliers=showfliers)
    ax.set(xlabel="Time in ms", ylabel="")
    plt.yticks(plt.yticks()[0], sorted_keys)
    ax.set_title(title)
    plt.tight_layout()
    plt.savefig("output-string.png")
if __name__ == '__main__':
    main()

Antwoord 6

1. met behulp van slice-notatie

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

2. de functie reversed() gebruiken

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

3. recursie gebruiken

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

Antwoord 7

Een minder verwarrende manier om ernaar te kijken zou zijn:

string = 'happy'
print(string)

‘gelukkig’

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

‘yppah’

In het Engels luidt [-1::-1] als:

“Begin bij -1, ga helemaal en neem stappen van -1”


Antwoord 8

Een string in python omkeren zonder reversed() of [::-1] te gebruiken

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

Antwoord 9

Dit is ook een interessante manier:

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

of vergelijkbaar:

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

Nog een meer ‘exotische’ manier om bytearray te gebruiken die .reverse() ondersteunt

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

zal produceren:

'!siht esreveR'

Antwoord 10

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

Antwoord 11

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"

Dit werkt door een string door te lussen en de waarden in omgekeerde volgorde toe te wijzen aan een andere string.


Antwoord 12

original = "string"
rev_index = original[::-1]
rev_func = list(reversed(list(original))) #nsfw
print(original)
print(rev_index)
print(''.join(rev_func))

Antwoord 13

Om dit op een programmeerbare manier op te lossen voor een interview

def reverse_a_string(string: str) -> str:
    """
    This method is used to reverse a string.
    Args:
        string: a string to reverse
    Returns: a reversed string
    """
    if type(string) != str:
        raise TypeError("{0} This not a string, Please provide a string!".format(type(string)))
    string_place_holder = ""
    start = 0
    end = len(string) - 1
    if end >= 1:
        while start <= end:
            string_place_holder = string_place_holder + string[end]
            end -= 1
        return string_place_holder
    else:
        return string
a = "hello world"
rev = reverse_a_string(a)
print(rev)

Uitvoer:

dlrow olleh

Antwoord 14

a=input()
 print(a[::-1])

De bovenstaande code ontvangt de invoer van de gebruiker en drukt een uitvoer af die gelijk is aan het omgekeerde van de invoer door [::-1] toe te voegen.

OUTPUT:

>>> Happy 
>>> yppaH

Maar als het om zinnen gaat, bekijk dan de code hieronder:

>>> Have a happy day
>>> yad yppah a evaH

Maar als je wilt dat alleen de tekens van de tekenreeks worden omgekeerd en niet de reeks, probeer dan dit:

a=input().split() #Splits the input on the basis of space (" ")
for b in a: #declares that var (b) is any value in the list (a)
    print(b[::-1], end=" ") #End declares to print the character in its quotes (" ") without a new line.

In de bovenstaande code in regel 2 in zei ik dat ** variabele b elke waarde in de lijst is (a)** Ik zei var a om een lijst te zijn, want wanneer je split in een invoer gebruikt, de variabele van de invoer wordt een lijst. Onthoud ook dat split niet kan worden gebruikt in het geval van int(input())

OUTPUT:

>>> Have a happy day
>>> evaH a yppah yad

Als we end(” “) niet toevoegen aan de bovenstaande code, wordt het als volgt afgedrukt:

>>> Have a happy day
>>> evaH
>>> a
>>> yppah
>>> yad

Hieronder is een voorbeeld om end() te begrijpen:

CODE:

for i in range(1,6):
     print(i) #Without end()

OUTPUT:

>>> 1
>>> 2
>>> 3
>>> 4
>>> 5

Nu coderen met end():

for i in range(1,6):
    print(i, end=" || ")

OUTPUT:

>>> 1 || 2 || 3 || 4 || 5 ||

Antwoord 15

Hier is een geen fancy:

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!")

Antwoord 16

Hier is er een zonder [::-1]of reversed(voor leerdoeleinden):

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")

je kunt +=gebruiken om strings samen te voegen, maar join()is sneller.


Antwoord 17

Recursieve methode:

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

voorbeeld:

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

Antwoord 18

Alle bovenstaande oplossingen zijn perfect, maar als we proberen een string om te keren met for-lus in python, wordt het een beetje lastig, dus hier is hoe we een string kunnen omkeren met for-lus

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

Ik hoop dat deze iemand nuttig zal zijn.


Antwoord 19

Er zijn veel manieren om een string om te draaien, maar ik heb er ook nog een gemaakt, gewoon voor de lol. Ik denk dat deze aanpak niet zo slecht is.

def reverse(_str):
    list_char = list(_str) # Create a hypothetical list. because string is immutable
    for i in range(len(list_char)/2): # just t(n/2) to reverse a big string
        list_char[i], list_char[-i - 1] = list_char[-i - 1], list_char[i]
    return ''.join(list_char)
print(reverse("Ehsan"))

Antwoord 20

Natuurlijk, in Python kun je hele mooie 1-regelige dingen doen. 🙂
Hier is een eenvoudige, allesomvattende oplossing die in elke programmeertaal zou kunnen werken.

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)

Antwoord 21

s = 'hello'
ln = len(s)
i = 1
while True:
    rev = s[ln-i]
    print rev,
    i = i + 1
    if i == ln + 1 :
        break

output:

o l l e h

Antwoord 22

U kunt de omgekeerde functie gebruiken met een lijst Bevrijd. Maar ik begrijp niet waarom deze methode is geëlimineerd in Python 3, was onnodig.

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

Other episodes