Reputation: 40231
There is no built in reverse
method for Python's str
object. How can I reverse a string?
Upvotes: 1689
Views: 1662090
Reputation: 461
Using For loop
name = 'Python'
strnew = ""
for i in name:
strnew = i+strnew
print("After reverse string " +strnew)
Upvotes: -1
Reputation: 136177
This answer is a bit longer and contains 3 sections: Benchmarks of existing solutions, why most solutions here are wrong, my solution.
The existing answers are only correct if Unicode Modifiers / grapheme clusters are ignored. I'll deal with that later, but first have a look at the speed of some reversal algorithms:
NOTE: I've what I called list_comprehension
should be called slicing
slicing : 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
slicing : 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
You can see that the time for the slicing (reversed = string[::-1]
) is in all cases by far the lowest (even after fixing my typo).
If you really want to reverse a string in the common sense, it is WAY more complicated. For example, take the following string (brown finger pointing left, yellow finger pointing up). Those are two graphemes, but 3 unicode code points. The additional one is a skin modifier.
example = "👈🏾👆"
But if you reverse it with any of the given methods, you get brown finger pointing up, yellow finger pointing left. The reason for this is that the "brown" color modifier is still in the middle and gets applied to whatever is before it. So we have
and
original: LMU 👈🏾👆
reversed: UML (above solutions) ☝🏾👈
reversed: ULM (correct reversal) 👆👈🏾
Unicode Grapheme Clusters are a bit more complicated than just modifier code points. Luckily, there is a library for handling graphemes:
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
and hence the correct answer would be
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
which also is by far the slowest:
slicing : 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
#!/usr/bin/env python3
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 = [(slicing, 'slicing', 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 slicing(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()
Upvotes: 66
Reputation: 488334
Using slicing:
>>> 'hello world'[::-1]
'dlrow olleh'
Slice notation takes the form [start:stop:step]
. In this case, we omit the start
and stop
positions since we want the whole string. We also use step = -1
, which means, "repeatedly step from right to left by 1 character".
Upvotes: 3107
Reputation: 32360
### example01 -------------------
mystring = 'coup_ate_grouping'
backwards = mystring[::-1]
print(backwards)
### ... or even ...
mystring = 'coup_ate_grouping'[::-1]
print(mystring)
### result01 -------------------
'''
gnipuorg_eta_puoc
'''
This answer is provided to address the following concern from @odigity:
Wow. I was horrified at first by the solution Paolo proposed, but that took a back seat to the horror I felt upon reading the first comment: "That's very pythonic. Good job!" I'm so disturbed that such a bright community thinks using such cryptic methods for something so basic is a good idea. Why isn't it just s.reverse()?
string.reverse()
string.reverse()
to avoid slice notation.print 'coup_ate_grouping'[-4:] ## => 'ping'
print 'coup_ate_grouping'[-4:-1] ## => 'pin'
print 'coup_ate_grouping'[-1] ## => 'g'
[-1]
may throw some developers offPython has a special circumstance to be aware of: a string is an iterable type.
One rationale for excluding a string.reverse()
method is to give python developers incentive to leverage the power of this special circumstance.
In simplified terms, this simply means each individual character in a string can be easily operated on as a part of a sequential arrangement of elements, just like arrays in other programming languages.
To understand how this works, reviewing example02 can provide a good overview.
### 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'
The cognitive load associated with understanding how slice notation works in python may indeed be too much for some adopters and developers who do not wish to invest much time in learning the language.
Nevertheless, once the basic principles are understood, the power of this approach over fixed string manipulation methods can be quite favorable.
For those who think otherwise, there are alternate approaches, such as lambda functions, iterators, or simple one-off function declarations.
If desired, a developer can implement her own string.reverse() method, however it is good to understand the rationale behind this aspect of python.
Upvotes: 47
Reputation: 856
This is also an interesting way:
def reverse_words_1(s):
rev = ''
for i in range(len(s)):
j = ~i # equivalent to j = -(i + 1)
rev += s[j]
return rev
or similar:
def reverse_words_2(s):
rev = ''
for i in reversed(range(len(s)):
rev += s[i]
return rev
Another more 'exotic' way using bytearray which supports .reverse()
b = bytearray('Reverse this!', 'UTF-8')
b.reverse()
b.decode('UTF-8')`
will produce:
'!siht esreveR'
Upvotes: 5
Reputation: 708
a=input()
print(a[::-1])
The above code recieves the input from the user and prints an output that is equal to the reverse of the input by adding [::-1].
OUTPUT:
>>> Happy
>>> yppaH
But when it comes to the case of sentences, view the code output below:
>>> Have a happy day
>>> yad yppah a evaH
But if you want only the characters of the string to be reversed and not the sequence of string, try this:
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 the above code in line 2 in I said that ** variable b is any value in the list (a)** I said var a to be a list because when you use split in an input the variable of the input becomes a list. Also remember that split can't be used in the case of int(input())
OUTPUT:
>>> Have a happy day
>>> evaH a yppah yad
If we don't add end(" ") in the above code then it will print like the following:
>>> Have a happy day
>>> evaH
>>> a
>>> yppah
>>> yad
Below is an example to understand end():
CODE:
for i in range(1,6):
print(i) #Without end()
OUTPUT:
>>> 1
>>> 2
>>> 3
>>> 4
>>> 5
Now code with end():
for i in range(1,6):
print(i, end=" || ")
OUTPUT:
>>> 1 || 2 || 3 || 4 || 5 ||
Upvotes: 0
Reputation: 413
To solve this in programing way for 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)
Output:
dlrow olleh
Upvotes: 1
Reputation: 625
Recursive method:
def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1])
example:
print(reverse("Hello!")) #!olleH
Upvotes: -1
Reputation: 394775
What is the best way of implementing a reverse function for strings?
My own experience with this question is academic. However, if you're a pro looking for the quick answer, use a slice that steps by -1
:
>>> 'a string'[::-1]
'gnirts a'
or more readably (but slower due to the method name lookups and the fact that join forms a list when given an iterator), str.join
:
>>> ''.join(reversed('a string'))
'gnirts a'
or for readability and reusability, put the slice in a function
def reversed_string(a_string):
return a_string[::-1]
and then:
>>> reversed_string('a_string')
'gnirts_a'
If you're interested in the academic exposition, please keep reading.
There is no built-in reverse function in Python's str object.
Here is a couple of things about Python's strings you should know:
In Python, strings are immutable. Changing a string does not modify the string. It creates a new one.
Strings are sliceable. Slicing a string gives you a new string from one point in the string, backwards or forwards, to another point, by given increments. They take slice notation or a slice object in a subscript:
string[subscript]
The subscript creates a slice by including a colon within the braces:
string[start:stop:step]
To create a slice outside of the braces, you'll need to create a slice object:
slice_obj = slice(start, stop, step)
string[slice_obj]
While ''.join(reversed('foo'))
is readable, it requires calling a string method, str.join
, on another called function, which can be rather relatively slow. Let's put this in a function - we'll come back to it:
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
Much faster is using a reverse slice:
'foo'[::-1]
But how can we make this more readable and understandable to someone less familiar with slices or the intent of the original author? Let's create a slice object outside of the subscript notation, give it a descriptive name, and pass it to the subscript notation.
start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]
To actually implement this as a function, I think it is semantically clear enough to simply use a descriptive name:
def reversed_string(a_string):
return a_string[::-1]
And usage is simply:
reversed_string('foo')
If you have an instructor, they probably want you to start with an empty string, and build up a new string from the old one. You can do this with pure syntax and literals using a while loop:
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
This is theoretically bad because, remember, strings are immutable - so every time where it looks like you're appending a character onto your new_string
, it's theoretically creating a new string every time! However, CPython knows how to optimize this in certain cases, of which this trivial case is one.
Theoretically better is to collect your substrings in a list, and join them later:
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)
However, as we will see in the timings below for CPython, this actually takes longer, because CPython can optimize the string concatenation.
Here are the timings:
>>> 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 optimizes string concatenation, whereas other implementations may not:
... do not rely on CPython's efficient implementation of in-place string concatenation for statements in the form a += b or a = a + b . This optimization is fragile even in CPython (it only works for some types) and isn't present at all in implementations that don't use refcounting. In performance sensitive parts of the library, the ''.join() form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.
Upvotes: 320
Reputation: 1560
A lesser perplexing way to look at it would be:
string = 'happy'
print(string)
'happy'
string_reversed = string[-1::-1]
print(string_reversed)
'yppah'
In English [-1::-1] reads as:
"Starting at -1, go all the way, taking steps of -1"
Upvotes: 12
Reputation: 4764
Here is a no fancy one:
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!")
Upvotes: 1
Reputation: 3137
Reverse a string in python without using reversed() or [::-1]
def reverse(test):
n = len(test)
x=""
for i in range(n-1,-1,-1):
x += test[i]
return x
Upvotes: 10
Reputation: 881439
@Paolo's s[::-1]
is fastest; a slower approach (maybe more readable, but that's debatable) is ''.join(reversed(s))
.
Upvotes: 309