42

I came across a strange Codecademy exercise that required a function that would take a string as input and return it in reverse order. The only problem was you could not use the reversed method or the common answer here on stackoverflow, [::-1].

Obviously in the real world of programming, one would most likely go with the extended slice method, or even using the reversed function but perhaps there is some case where this would not work?

I present a solution below in Q&A style, in case it is helpful for people in the future.

martineau
  • 119,623
  • 25
  • 170
  • 301
samrap
  • 5,595
  • 5
  • 31
  • 56

43 Answers43

67

You can also do it with recursion:

def reverse(text):
    if len(text) <= 1:
        return text

    return reverse(text[1:]) + text[0]

And a simple example for the string hello:

   reverse(hello)
 = reverse(ello) + h           # The recursive step
 = reverse(llo) + e + h
 = reverse(lo) + l + e + h
 = reverse(o) + l + l + e + h  # Base case
 = o + l + l + e + h
 = olleh
Blender
  • 289,723
  • 53
  • 439
  • 496
  • 1
    Best answer by far. Python wasn't geared for this kind of low-level programming without the use of its helpful constructs, but this is by far the best way to do so if you must. – Brian Peterson Sep 22 '13 at 02:46
  • 1
    I think this solution requires O(n^2) memory... this could be very bad for long strings. – Emanuele Paolini Jul 07 '14 at 21:13
  • 4
    @EmanuelePaolini: `[::-1]` is the only thing you should be using. All of these answers are just different ways of reversing a string, there are no speed guarantees. – Blender Jul 07 '14 at 22:17
  • @Blender Thanks for this breakdown, appreciate it. Just to be clear on what's happening here: is the text variable for `text[0`] basically storing each character it slices off as the recursive function calls keeps cycling through the string? or is it that with each recursive call another `text[0]` is being added? – AdjunctProfessorFalcon Jun 02 '15 at 18:12
  • 1
    @ChrisPurrone: The recursive function doesn't really "cycle" through the string (in CPython). Each time you call a function, a stack frame is created (which contains the local variables and the return value of your function). Your function is recursive, so each time you `return` something a new stack frame is created, but since the return value is dependent on another function's return value, the old stack frames still need to stick around. That's why I wrote the long chain of `+ h`'s. They aren't really concatenated until the very end, which is when the final function call returns a string. – Blender Jun 02 '15 at 22:59
  • @Blender So how you have all the strings being concatenated (until the final function call) is really just an way of describing how the strings that are sliced off by the `text[0]` are being stored in memory in each stack frame? Why is it that all the strings are only concatenated at the very end instead each string (in each stack frame) being added together? Sorry, newbie so struggling to understand how reverse(text[1:]0 and text[0] are working together here. – AdjunctProfessorFalcon Jun 02 '15 at 23:47
  • 2
    @ChrisPurrone: CPython doen't do any sort of recursion optimization at all (from what I remember). In fact, CPython doesn't even optimize tail recursive functions, which can be translated easily into equivalent iterative functions. – Blender Jun 02 '15 at 23:59
  • For my solution, I refactored this into a while loop to avoid recursion error on long strings. – krethika Jun 17 '15 at 22:50
19

Just another option:

from collections import deque
def reverse(iterable):
    d = deque()
    d.extendleft(iterable)
    return ''.join(d)
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
12

Use reversed range:

def reverse(strs):
    for i in xrange(len(strs)-1, -1, -1):
        yield strs[i]
...         
>>> ''.join(reverse('hello'))
'olleh'

xrange or range with -1 step would return items in reversed order, so we need to iterate from len(string)-1 to -1(exclusive) and fetch items from the string one by one.

>>> list(xrange(len(strs) -1, -1 , -1))
[4, 3, 2, 1, 0]  #iterate over these indexes and fetch the items from the string

One-liner:

def reverse(strs):
    return ''.join([strs[i] for i in xrange(len(strs)-1, -1, -1)])
... 
>>> reverse('hello')
'olleh'
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
11

EDIT

Recent activity on this question caused me to look back and change my solution to a quick one-liner using a generator:

rev = ''.join([text[len(text) - count] for count in xrange(1,len(text)+1)])

Although obviously there are some better answers here like a negative step in the range or xrange function. The following is my original solution:


Here is my solution, I'll explain it step by step

def reverse(text):

    lst = []
    count = 1

    for i in range(0,len(text)):

        lst.append(text[len(text)-count])
        count += 1

    lst = ''.join(lst)
    return lst

print reverse('hello')

First, we have to pass a parameter to the function, in this case text.

Next, I set an empty list, named lst to use later. (I actually didn't know I'd need the list until I got to the for loop, you'll see why it's necessary in a second.)

The count variable will make sense once I get into the for loop

So let's take a look at a basic version of what we are trying to accomplish:

It makes sense that appending the last character to the list would start the reverse order. For example:

>>lst = []
>>word = 'foo'
>>lst.append(word[2])
>>print lst
['o']

But in order to continue reversing the order, we need to then append word[1] and then word[0]:

>>lst.append(word[2])
>>lst.append(word[1])
>>lst.append(word[0])
>>print lst
['o','o','f']

This is great, we now have a list that has our original word in reverse order and it can be converted back into a string by using .join(). But there's a problem. This works for the word foo, it even works for any word that has a length of 3 characters. But what about a word with 5 characters? Or 10 characters? Now it won't work. What if there was a way we could dynamically change the index we append so that any word will be returned in reverse order?

Enter for loop.

for i in range(0,len(text)):

    lst.append(text[len(text)-count])
    count += 1

First off, it is necessary to use in range() rather than just in, because we need to iterate through the characters in the word, but we also need to pull the index value of the word so that we change the order.

The first part of the body of our for loop should look familiar. Its very similar to

>>lst.append(word[..index..])

In fact, the base concept of it is exactly the same:

>>lst.append(text[..index..])

So what's all the stuff in the middle doing?

Well, we need to first append the index of the last letter to our list, which is the length of the word, text, -1. From now on we'll refer to it as l(t) -1

>>lst.append(text[len(text)-1])

That alone will always get the last letter of our word, and append it to lst, regardless of the length of the word. But now that we have the last letter, which is l(t) - 1, we need the second to last letter, which is l(t) - 2, and so on, until there are no more characters to append to the list. Remember our count variable from above? That will come in handy. By using a for loop, we can increment the value of count by 1 through each iteration, so that the value we subtract by increases, until the for loop has iterated through the entire word:

>>for i in range(0,len(text)):
..        
..      lst.append(text[len(text)-count])
..      count += 1

Now that we have the heart of our function, let's look at what we have so far:

def reverse(text):

    lst = []
    count = 1

    for i in range(0,len(text)):

        lst.append(text[len(text)-count])
        count += 1

We're almost done! Right now, if we were to call our function with the word 'hello', we would get a list that looks like:

['o','l','l','e','h']

We don't want a list, we want a string. We can use .join for that:

def reverse(text):

    lst = []
    count = 1

    for i in range(0,len(text)):

        lst.append(text[len(text)-count])
        count += 1

    lst = ''.join(lst) # join the letters together without a space
    return lst

And that's it. If we call the word 'hello' on reverse(), we'd get this:

>>print reverse('hello')
olleh

Obviously, this is way more code than is necessary in a real life situation. Using the reversed function or extended slice would be the optimal way to accomplish this task, but maybe there is some instance when it would not work, and you would need this. Either way, I figured I'd share it for anyone who would be interested.

If you guys have any other ideas, I'd love to hear them!

samrap
  • 5,595
  • 5
  • 31
  • 56
  • I think this line is missing a `-1` in the subscript of `text`: `lst.append(text[len(text)-count])` – Ketan Maheshwari Dec 12 '13 at 02:28
  • No, that would only be necessary if `count` started at 0, it starts at 1 – samrap Dec 12 '13 at 02:36
  • Looking back, this can be reduced to one line: `[text[len(text) - count] for count in xrange(1,len(text)+1)]` – samrap Dec 12 '13 at 02:41
  • True. I find this slightly changed version more readable somehow: `[text[len(text) - 1 - count] for count in xrange(len(text))]` – Ketan Maheshwari Dec 12 '13 at 02:47
  • Definitely more readable, though now that I have more Python experience I would go with a more readable comprehension like some of the answers here – samrap Dec 12 '13 at 02:48
7

Only been coding Python for a few days, but I feel like this was a fairly clean solution. Create an empty list, loop through each letter in the string and append it to the front of the list, return the joined list as a string.

def reverse(text):
backwardstext = []
for letter in text:
    backwardstext.insert(0, letter)
return ''.join(backwardstext)
user3355359
  • 71
  • 1
  • 1
6

I used this:

def reverse(text):
s=""
l=len(text)
for i in range(l):
    s+=text[l-1-i]
return s
Sumit Kushwaha
  • 378
  • 4
  • 9
4

Inspired by Jon's answer, how about this one

word = 'hello'
q = deque(word)
''.join(q.pop() for _ in range(len(word)))
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
4

This is a very interesting question, I will like to offer a simple one liner answer:

>>> S='abcdefg'
>>> ''.join(item[1] for item in sorted(enumerate(S), reverse=True))
'gfedcba'

Brief explanation:

enumerate() returns [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), (6, 'g')]. The indices and the values. To reverse the values, just reverse sort it by sorted(). Finally, just put it together back to a str

CT Zhu
  • 52,648
  • 17
  • 120
  • 133
  • 2
    wow this is the coolest answer on here, very unique. One question though, why is it join item[1] and not just join item? – samrap Sep 22 '13 at 02:40
  • The `item`s will be like `(0,'a')`, tuples of a `int` (the index) and a `str` (the value), so you can't just `.join()` them. :-P – CT Zhu Sep 22 '13 at 02:47
3

I created different versions of how to reverse a string in python in my repo: https://github.com/fedmich/Python-Codes/tree/master/Reverse%20a%20String

You can do it by using list-comprehension or lambda technique:

# Reverse a string without using reverse() function
s = 'Federico';
li = list( s )  #convert string to list

ret = [ li[i-1] for i in xrange(len(li),0,-1)  ]    #1 liner lambda
print ( "".join( ret ) )

or by doing a backward for loop

# Reverse a string without using reverse() function
s = 'Federico';
r = []

length = len(s)
for i in xrange(length,0,-1):
    r.append( s[ i - 1] )

print ( "".join(r) )
fedmich
  • 5,343
  • 3
  • 37
  • 52
  • 1
    nice! I'm so stoked that people continue to find this a useful and interesting thread. Love seeing all the answers! – samrap Jun 02 '14 at 22:26
3
reduce(lambda x, y : y + x, "hello world")
Vinod Puliyadi
  • 225
  • 1
  • 3
  • 14
2

A golfed version: r=lambda x:"".join(x[i] for i in range(len(x-1),-1,-1)).

rlms
  • 10,650
  • 8
  • 44
  • 61
2

i just solved this in code academy and was checking my answers and ran across this list. so with a very limited understanding of python i just did this and it seamed to work.

def reverse(s):
    i = len(s) - 1
    sNew = ''
    while  i >= 0:
        sNew = sNew + str(s[i])
        i = i -1
    return sNew
dewetha
  • 21
  • 2
2
def reverse(s):
    return "".join(s[i] for i in range(len(s)-1, -1, -1))
CrackSmoker9000
  • 319
  • 4
  • 13
2

Blender's answer is lovely, but for a very long string, it will result in a whopping RuntimeError: maximum recursion depth exceeded. One might refactor the same code into a while loop, as one frequently must do with recursion in python. Obviously still bad due to time and memory issues, but at least will not error.

def reverse(text):
    answer = ""
    while text:
        answer = text[0] + answer
        text = text[1:]
    return answer
krethika
  • 3,908
  • 1
  • 24
  • 27
1

Today I was asked this same exercise on pen&paper, so I come up with this function for lists:

def rev(s):
  l = len(s)
  for i,j in zip(range(l-1, 0, -1), range(l//2)):
    s[i], s[j] = s[j], s[i]
  return s

which can be used with strings with "".join(rev(list("hello")))

berdario
  • 1,851
  • 18
  • 29
1

This is a way to do it with a while loop:

def reverse(s):
    t = -1
    s2 = ''
    while abs(t) < len(s) + 1: 
        s2 = s2 + s[t]
        t  = t - 1
    return s2
sashkello
  • 17,306
  • 24
  • 81
  • 109
PythonSam
  • 11
  • 1
1

I have also just solved the coresponding exercise on codeacademy and wanted to compare my approach to others. I have not found the solution I used so far, so I thought that I sign up here and provide my solution to others. And maybe I get a suggestion or a helpful comment on how to improve the code.

Ok here it goes, I did not use any list to store the string, instead I have just accessed the string index. It took me a bit at first to deal with the len() and index number, but in the end it worked :).

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

I am still wondering if the reversestring = "" could be solved in a more elegant way, or if it is "bad style" even, but i couldn't find an answer so far.

Fadeiar
  • 11
  • 1
  • That's a good one, one way to save the string more elegantly would be to turn your loop into a list comprehension and then return a str of the list with the `join` function: `return ''.join([x[n] for n in range(len(x)-1, -1, -1)])` This is a simple one-liner. Also there is no need for `str()` in your range assuming x is already a string. Not sure if you've done list comprehensions yet in Python. When you have this will make more sense. Great job! :) – samrap Mar 26 '14 at 22:16
  • Thank's a lot for your reply i have just moved on with the challenges on codeacademy and I could really make use of your hint :). After reading a little bit on list comprehension I was able to use your input for a function that kicks out all vowels in a string. `def anti_vowel(text): vowels = "aeiou" return "".join(n for n in text if not n.lower() in vowels)` Thanks a lot @samrap (can't give reputation points yet) – Fadeiar Mar 27 '14 at 12:08
1
def reverse(text):
    a=""
    l=len(text)
    while(l>=1):
        a+=text[l-1]
        l-=1
    return a

i just concatenated the string a with highest indexes of text (which keeps on decrementing by 1 each loop).

1

All I did to achieve a reverse string is use the xrange function with the length of the string in a for loop and step back per the following:

myString = "ABC"

for index in xrange(len(myString),-1):
    print index

My output is "CBA"

falsarella
  • 12,217
  • 9
  • 69
  • 115
1

You can simply reverse iterate your string starting from the last character. With python you can use list comprehension to construct the list of characters in reverse order and then join them to get the reversed string in a one-liner:

def reverse(s):
  return "".join([s[-i-1] for i in xrange(len(s))])

if you are not allowed to even use negative indexing you should replace s[-i-1] with s[len(s)-i-1]

Emanuele Paolini
  • 9,912
  • 3
  • 38
  • 64
1

You've received a lot of alternative answers, but just to add another simple solution -- the first thing that came to mind something like this:

def reverse(text):
    reversed_text = ""   

    for n in range(len(text)):
        reversed_text += text[-1 - n]

    return reversed_text

It's not as fast as some of the other options people have mentioned(or built in methods), but easy to follow as we're simply using the length of the text string to concatenate one character at a time by slicing from the end toward the front.

PerryAJ
  • 106
  • 1
  • 4
  • +1 Didn't even know you could do this, or maybe I did at one point I just haven't worked with Python in 4 or 5 months. Either way, good job – samrap Sep 15 '14 at 00:09
1
def reverseThatString(theString):
    reversedString = ""
    lenOfString = len(theString)
    for i,j in enumerate(theString):
        lenOfString -= 1
        reversedString += theString[lenOfString]
    return reversedString
1

This is my solution using the for i in range loop:

def reverse(string):
    tmp = ""
    for i in range(1,len(string)+1):
        tmp += string[len(string)-i]            
    return tmp

It's pretty easy to understand. I start from 1 to avoid index out of bound.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Stefano Saitta
  • 1,844
  • 1
  • 19
  • 34
1

You can do simply like this

def rev(str):
   rev = ""
   for i in range(0,len(str)):
   rev = rev + str[(len(str)-1)-i]
   return rev
Vijay
  • 924
  • 1
  • 12
  • 27
1

Here's my contribution:

def rev(test):  
    test = list(test)
    i = len(test)-1
    result = []

    print test
    while i >= 0:
        result.append(test.pop(i))
        i -= 1
    return "".join(result)
fra
  • 205
  • 1
  • 3
  • 7
1

Here is one using a list as a stack:

def reverse(s):
  rev = [_t for _t in s]
  t = ''
  while len(rev) != 0:
    t+=rev.pop()
  return t
user2399453
  • 2,930
  • 5
  • 33
  • 60
1

Try this simple and elegant code.

my_string= "sentence"
new_str = ""
for i in my_string:
    new_str = i + new_str
print(new_str)
SamTheProgrammer
  • 1,051
  • 1
  • 10
  • 28
0

you have got enough answer.

Just want to share another way.

you can write a two small function for reverse and compare the function output with the given string

var = ''

def reverse(data):

for i in data:
    var = i + var
return var

if not var == data :

print "No palindrome"

else :

print "Palindrome"

rajpython
  • 179
  • 2
  • 3
  • 14
0

Not very clever, but tricky solution

def reverse(t):
    for j in range(len(t) // 2):
        t = t[:j] + t[- j - 1] + t[j + 1:- j - 1] + t[j] + t[len(t) - j:]
    return t
Dmitry_Kovalov
  • 1,924
  • 1
  • 14
  • 11
  • 1
    It is better for the OP if you can add some more information on an Answer such as this. Others looking at this in future will all benefit. – Deepend Jul 07 '14 at 21:25
  • Agreed with @deepend also I like this answer it is similar to the way it is done in K&R's C Programming Language book – samrap Jul 09 '14 at 17:34
0

Pointfree:

from functools import partial
from operator import add

flip = lambda f: lambda x, y: f(y, x)
rev = partial(reduce, flip(add))

Test:

>>> rev('hello')
'olleh'
pillmuncher
  • 10,094
  • 2
  • 35
  • 33
0

The way I can think of without using any built-in functions:

a = 'word'
count = 0
for letter in a:
    count += 1

b = ''
for letter in a:
    b += a[count-1]
    count -= 1

And if you print b:

print b
drow
0

My solution:

s = raw_input("Enter string ")
print
def reverse(text):

st = ""  
rev = ""  
count = len(text)  
print "Lenght of text: ", len(text)  
print  
for c in range(len(text)):  
    count = count - 1  
    st = st + "".join(text[c])  
    rev = rev + "".join(text[count])  
    print "count:       ", count  
    print "print c:     ", c  
    print "text[c]:     ", text[c]  
    print  
print "Original:    ", st  
print "Reversed:    ", rev  
return rev  

reverse(s)

Result screen

Enter string joca

Lenght of text: 4

count: 3
print c: 0
text[c]: j

count: 2
print c: 1
text[c]: o

count: 1
print c: 2
text[c]: c

count: 0
print c: 3
text[c]: a

Original: joca
Reversed: acoj
None

Jovica
  • 9
  • 1
  • 3
0

This is the simplest way in python 2.7 syntax

def reverse(text):

      rev = ""
      final = ""

      for a in range(0,len(text)):
            rev = text[len(text)-a-1]
            final = final + rev
return final
Community
  • 1
  • 1
AceRam
  • 279
  • 3
  • 6
0
m = input("Enter string::")
def rev(s):
    z = -1
    x = len(s)
    while x != 0:
        print(s[z], end='')
        z = z-1
        x = x-1
rev(m)
bfontaine
  • 18,169
  • 13
  • 73
  • 107
chandra
  • 11
  • 1
0
enterString=input("Enter a string to be reversed:")
string_List=list(enterString)
revedString=[]

for i in range(len(string_List)):
    revedString.append(string_List.pop())
#Pop last element and append it to the empty list
print "reversed string is:",''.join(revedString)
#as the out come is in list convert it into string using .join

Sample Output:
>>>Enter a string to be reversed :sampleReverse1  
>>>reversed string is:1esreveRelpmas 
Sanyal
  • 864
  • 10
  • 22
0

I prefer this as the best way of reversing a string using a for loop.

def reverse_a_string(str): 

    result=" "
    for i in range(len(str),1,-1):
        result= result+ str[i-1]
    return result

print reverse_a_string(input())
Kapilfreeman
  • 897
  • 9
  • 10
0

You can simply use the pop as suggested. Here are one liners fot that

chaine = 'qwertyuiop'
''.join([chaine[-(x + 1)] for x in range(len(chaine))])
'poiuytrewq'
gg = list(chaine)
''.join([gg.pop() for _ in range(len(gg))])
'poiuytrewq'
cgte
  • 440
  • 4
  • 10
0

Simple Method,

>>> a = "hi hello"
>>> ''.join([a[len(a)-i-1] for i,j in enumerate(a)])
'olleh ih'
>>> 
Mohideen bin Mohammed
  • 18,813
  • 10
  • 112
  • 118
0

simply run this but it would print each character in a separate line the second version prints it in one line.

def rev(str):
        for i in range(0,len(str)):
            print(list(str)[len(str)-i-1])

Print in one line:

def rev(str):
    rev = list()
    for i in range(0,len(str)):
        rev.append((list(str)[len(str)-i-1]))
    print(''.join(rev))
jax
  • 840
  • 2
  • 17
  • 35
0

I have got an example to reverse strings in python from thecrazyprogrammer.com:

string1 =  "IkNoWwHeReYoUlIvE"
string2 = ""

i = len(string1)-1

while(i>=0):
  string2 = string2 + string1[i]
  i = i-1

print("original = " + string1)
print("reverse  = " + string2)
monkey
  • 526
  • 7
  • 21
-1

We can first convert string into a list and then reverse the string after that use ".join" method to again convert list to single string.

text="Youknowwhoiam"
lst=list(text)
lst.reverse()
print("".join(lst))

It will first convert "youknowwhoiam" into ['Y', 'o', 'u', 'k', 'n', 'o', 'w', 'w', 'h', 'o', 'i', 'a', 'm']

After it will reverse the list into ['m', 'a', 'i', 'o', 'h', 'w', 'w', 'o', 'n', 'k', 'u', 'o', 'Y']

In last it will convert list into single word "maiohwwonkuoY "

For more explanation in brief just run this code:-

text="Youknowwhoiam"
lst=list(text)
print (lst)
lst.reverse()
print(lst)
print("".join(lst))
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88
-3
__author__ = 'Sreedhar'
#find reverse of the string with out using index or reverse function?

def reverse(text):
    revs = ""
    for i in text:
        revs = i + revs
    return revs

strig = raw_input("enter anything:")

print reverse(strig)

#index method
print strig[::-1]
JJJ
  • 32,902
  • 20
  • 89
  • 102
-8

Easiest way to reverse a string:

    backwards = input("Enter string to reverse: ")
    print(backwards[::-1])