3

I know I could just use the reverse function to reverse a string, but for a Codecademy assignment I'm attempting to reverse a string without reverse or [::-1]. In attempting to find out what's wrong with my code, I've stumbled upon possible solutions to the problem, but at this point, I just want to understand what my code is doing.

def reverse(text):
    text2 = list(text)
    backwards = []
    for char in text2:
        backwards.append(text2[-1])
        del(text2[-1])
    return "".join(backwards)

text = raw_input("Say something:\n")

print reverse(text)

When I test this, the output is always the last half of the string reversed. I don't understand why for char in text2: would be interpreted as for half_the_char in text2. What about my code accounts for that oddity?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
thektulu7
  • 45
  • 6

3 Answers3

4

You are looping over the list and removing from it. So by the time you get to the halfway point, the second half of the list is gone and the for loop stops because there are no more items to iterate over anymore.

Print out your list each iteration and you'll see what is happening:

>>> text2 = list('hello')
>>> backwards = []
>>> for char in text2:
...     backwards.append(text2[-1])
...     del text2[-1]
...     print 'char:', char, 'backwards:', backwards, 'text2:', text2
... 
char: h, backwards: ['o'] text2: ['h', 'e', 'l', 'l']
char: e, backwards: ['o', 'l'] text2: ['h', 'e', 'l']
char: l, backwards: ['o', 'l', 'l'] text2: ['h', 'e']

The for loop then stops, because there is no more items to iterate over left; after iterating over indexes 0, 1 and 2, the list has been shortened to the point where there is no index 3 anymore.

You could use a while loop instead:

while text2:
    backwards.append(text2[-1])
    del(text2[-1])

Now the loop only stops when text2 is entirely empty.

Or you could loop over text, which has the same length and the same characters in it; it is almost as pointless as your original for loop because you ignore the char loop target just the same:

for char in text:
    backwards.append(text2[-1])
    del(text2[-1])

but text at least is not being shortened as you loop, so your iteration doesn't end prematurely.

Or you could use a separate index to pick the character to add, adjusting it each iteration, and then not delete from text2:

index = -1
for character in text2:
    backwards.append(text2[index])
    index -= 1

Now you'll iterate len(text2) times. Of course, you then don't need to convert text to a list anymore, you could just index into text.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • In that case, though, the 'h' and 'e' are still in `text2`, so it looks to me like they _are_ still available to be transferred. In all three shown iterations, the letters collectively make up "hello." The first half of the list is still there. – thektulu7 Oct 08 '15 at 14:24
  • @thektulu7: but the `for` loop is no longer iterating. It has already *passed* those characters. – Martijn Pieters Oct 08 '15 at 14:26
  • After seeing your most recent edit, I think I get it now. Thanks! – thektulu7 Oct 08 '15 at 14:36
  • @thektulu7: the `for` loop can't go *back* to those two characters. The list iterator uses an index, so first you get `text2[0]`, then the next iteration you get `text2[1]`, then `text2[2]`. But because you deleted elements from the list, there is no `text2[3]` *anymore*, so the loop stops. – Martijn Pieters Oct 08 '15 at 14:37
2

You are deleting the values from the original list

del(text2[-1])

Let's consider an example string "star", index would be 0-3. In first iteration, you add 'r' to backwards list and then delete 'r' (last character) from original list, so now you have "sta" string left, but your number of iterations are reduced to 3. Loop keeps deleting and reducing list size, resulting in less iterations. This causes earlier termination of loop.

Xoul
  • 359
  • 1
  • 3
  • 13
  • 1
    Note that they delete the last character so 'r' is deleted then 'a'. Deleting from the front would skip characters, deleting from the end just terminates the `for` early. – Duncan Oct 08 '15 at 14:17
  • My bad. Let me fix that. Thanks! – Xoul Oct 08 '15 at 14:18
  • So does the loop consider the deletion to be, in a way, not only a deletion of the character, but a deletion of an iteration? – thektulu7 Oct 08 '15 at 14:31
0

The line del(text2[-1]) accounts for your oddity. You are setpping along every character, but for every character you step, you delete one from the end, so your string will have nothing more left once you get half way through.

Rather than deleting the original characters, prepend the one you are iterating over:

for char in text2:
    backwards.insert(0, char)

See this question for reference: What's the idiomatic syntax for prepending to a short python list?

Another option is to iterate over the string backwards and append to the list:

for i in range(len(text2)):
    backwards.append(text2[-(i + 1)])
Community
  • 1
  • 1
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264