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 str
wordt 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:
-
In Python zijn strings onveranderlijk. Het wijzigen van een string verandert de string niet. Er wordt een nieuwe gemaakt.
-
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
- example01 produceert het gewenste resultaat, met behulp van uitgebreid Slice Notation .
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
- Zie b.v. example02
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)]