Reversing a string

S

Scott

Yeah I know strings == immutable, but question 1 in section 7.14 of "How to
think like a computer Scientist" has me trying to reverse one.

I've come up with two things, one works almost like it should except that
every traversal thru the string I've gotten it to repeat the "list" again.
This is what it looks like:

Code:
[QUOTE][QUOTE][QUOTE]
mylist = []
def rev(x):[/QUOTE][/QUOTE][/QUOTE]
            for char in x:
                mylist.append(char)
                mylist.reverse()
                print mylist

And the output that sorta works like it should, but threw a curveball, at me
looks like this:['t']
['h', 't']
['i', 't', 'h']
['s', 'h', 't', 'i']
[' ', 'i', 't', 'h', 's']
['i', 's', 'h', 't', 'i', ' ']
['s', ' ', 'i', 't', 'h', 's', 'i']
[' ', 'i', 's', 'h', 't', 'i', ' ', 's']
['j', 's', ' ', 'i', 't', 'h', 's', 'i', ' ']
['u', ' ', 'i', 's', 'h', 't', 'i', ' ', 's', 'j']
['s', 'j', 's', ' ', 'i', 't', 'h', 's', 'i', ' ', 'u']
['t', 'u', ' ', 'i', 's', 'h', 't', 'i', ' ', 's', 'j', 's']
[' ', 's', 'j', 's', ' ', 'i', 't', 'h', 's', 'i', ' ', 'u', 't']
['a', 't', 'u', ' ', 'i', 's', 'h', 't', 'i', ' ', 's', 'j', 's', ' ']
[' ', ' ', 's', 'j', 's', ' ', 'i', 't', 'h', 's', 'i', ' ', 'u', 't', 'a']
['t', 'a', 't', 'u', ' ', 'i', 's', 'h', 't', 'i', ' ', 's', 'j', 's', ' ',
' ']
['e', ' ', ' ', 's', 'j', 's', ' ', 'i', 't', 'h', 's', 'i', ' ', 'u', 't',
'a', 't']
['s', 't', 'a', 't', 'u', ' ', 'i', 's', 'h', 't', 'i', ' ', 's', 'j', 's',
' ', ' ', 'e']
['t', 'e', ' ', ' ', 's', 'j', 's', ' ', 'i', 't', 'h', 's', 'i', ' ', 'u',
't', 'a', 't', 's']


So I figured maybe make it a generator (I'm not TO familiar with generators
yet so don't laugh) which changed my code just a slight bit:

Code:
[QUOTE][QUOTE][QUOTE]
mylist = []
def rev(x):[/QUOTE][/QUOTE][/QUOTE]
            for char in x:
                mylist.append(char)
                mylist.reverse()
                yield mylist

But even that threw me a curveball:<generator object at 0x00D52170>

So how on earth would be the best way to: Write a function that takes a
string as an argument and outputs the letters backward, one per line.

It should look like the first char of every list in the top "working" code.

Any help woould be greatly apreciated, and a little bit of explaination as
to why you did it the way you did would be more helpful than just the code.

Thanks in advance
 
S

Stefan Behnel

Scott said:
So how on earth would be the best way to: Write a function that takes a
string as an argument and outputs the letters backward, one per line.

Homework?

Anyway, what about:

for c in string[::-1]:
print c


Stefan
 
W

Will Maier

So how on earth would be the best way to: Write a function that
takes a string as an argument and outputs the letters backward,
one per line.
... backward = list(forward)
... backward.reverse()
... return ''.join(backward) 'maps'

list.reverse() changes the list in-place. Instead of iterating over
the items in the string sequence, you can just convert the input
string outright.
 
D

Diez B. Roggisch

Scott said:
Yeah I know strings == immutable, but question 1 in section 7.14 of "How
to think like a computer Scientist" has me trying to reverse one.

I've come up with two things, one works almost like it should except that
every traversal thru the string I've gotten it to repeat the "list" again.
This is what it looks like:

Code:
[QUOTE][QUOTE]
mylist = []
def rev(x):[/QUOTE][/QUOTE]
for char in x:
mylist.append(char)
mylist.reverse()
print mylist

<snip/>

The reverse() is totally useless to apply each when appending each
character. Not only useless, but faulty: if you have a even number of
characters, your string won't be reversed.

All you need to do is this:
gfedcba


HTH Diez
 
N

Neil Cerutti

Yeah I know strings == immutable, but question 1 in section
7.14 of "How to think like a computer Scientist" has me trying
to reverse one.

No, it just wants to to print the characters in reverse, one per
line.
I've come up with two things, one works almost like it should
except that every traversal thru the string I've gotten it to
repeat the "list" again. This is what it looks like:

That's bad. If you need to use a list in the rev function, you
should bind a new list to a local variable inside rev.
for char in x:
mylist.append(char)
mylist.reverse()
print mylist

Here's an debugging exercise that you should try.

Please explain what you think each line in the above is supposed
to do. Pretend you are trying to convince me that the above
program works correctly. I bet you will see find your errors
right away as a result of this exercise.
So I figured maybe make it a generator (I'm not TO familiar
with generators yet so don't laugh) which changed my code just
a slight bit:

Experimentation with stuff you don't fully understand is a great
way to learn, but not that useful for solving exercises. ;)
 
P

ptn


That's bad. If you need to use a list in the rev function, you
should bind a new list to a local variable inside rev.

He's right. If you want to use a list to temporarily store the
reversed version of your string, it should exist only in the local
namespace of your function.

There's still stuff you can do with your function to make it work,
such as:
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:

So, big lessons: (1) Global variables suck if you try to manipulate
them and (2) in Python, if your code isn't as clear as you would like,
there's probably a better way to do it.
 
M

Martin Durkin

mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:
print "\n".join("spam"[::-1])

OK, maybe I'm missing the point here as I'm new to Python. The first one
seems clearer to me. What am I missing?

Martin
 
D

Duncan Booth

Martin Durkin said:
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:
print "\n".join("spam"[::-1])

OK, maybe I'm missing the point here as I'm new to Python. The first one
seems clearer to me. What am I missing?
I think all you are missing is familarity with Python, but I too don't like
one-liners simply for their own sake.

Slicing is one of Pythons great features, but even experienced programmers
often forget that you can have a third argument to a slice or that it can
even be negative.

The syntax for joining a sequence of strings with a separator is ugly, I
sometimes prefer to write it out as:
print str.join('\n', whatever)
or:
joinlines = '\n'.join
...
print joinlines(whatever)

but in this case I'd be as likely to go for an explicit loop for the print:

def rev(x):
for letter in x[::-1]:
print letter

which I think hits about the optimum between brevity and clarity. Your own
optimum point may of course vary.
 
M

Martin Durkin

Martin Durkin said:
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:

print "\n".join("spam"[::-1])

OK, maybe I'm missing the point here as I'm new to Python. The first
one seems clearer to me. What am I missing?
I think all you are missing is familarity with Python, but I too don't
like one-liners simply for their own sake.

I guess that's it. The first one reads more like a textbook example which
is about where I am at. Is there any speed benefit from the one liner?
thanks
Martin
 
S

Stefan Behnel

Martin said:
Martin Durkin said:
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:

print "\n".join("spam"[::-1])
OK, maybe I'm missing the point here as I'm new to Python. The first
one seems clearer to me. What am I missing?
I think all you are missing is familarity with Python, but I too don't
like one-liners simply for their own sake.

I guess that's it. The first one reads more like a textbook example which
is about where I am at. Is there any speed benefit from the one liner?

Almost definitely. But you can check yourself by using the timeit module.

Stefan
 
E

Evan Klitzke

Martin Durkin said:
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:

print "\n".join("spam"[::-1])


OK, maybe I'm missing the point here as I'm new to Python. The first
one seems clearer to me. What am I missing?
I think all you are missing is familarity with Python, but I too don't
like one-liners simply for their own sake.

I guess that's it. The first one reads more like a textbook example which
is about where I am at. Is there any speed benefit from the one liner?

The one line is quite a bit faster:

evan@thinkpad ~ $ python -m timeit 's = "onomatopoeia"; s = s.join(s[::-1])'
100000 loops, best of 3: 6.24 usec per loop

evan@thinkpad ~ $ python -m timeit '
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
return "".join(mylist)

s = "onomatopoeia"
s = rev(s)'
100000 loops, best of 3: 9.73 usec per loop
 
J

Jay Loden

Evan said:
I guess that's it. The first one reads more like a textbook example which
is about where I am at. Is there any speed benefit from the one liner?

The one line is quite a bit faster:

evan@thinkpad ~ $ python -m timeit 's = "onomatopoeia"; s = s.join(s[::-1])'
100000 loops, best of 3: 6.24 usec per loop

evan@thinkpad ~ $ python -m timeit '
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
return "".join(mylist)

s = "onomatopoeia"
s = rev(s)'
100000 loops, best of 3: 9.73 usec per loop


For what it's worth, with python 2.5 on my Macbook:

[jloden@macbook jloden]$ python -m timeit 's = "onomatopoeia"; s = s.join(s[::-1])'
100000 loops, best of 3: 5.2 usec per loop

[jloden@macbook jloden]$ python -m timeit '
def rev(x):
mylist = list(x)
mylist.reverse()
return "".join(mylist)

s = "onomatopoeia"
s = rev(s)'
100000 loops, best of 3: 3.94 usec per loop

Note that in the second version, I changed the code a little bit so that it no longer iterates over every char in the string and instead just calls lis() to convert it to a list of chars in order to call list.reverse() on it.

-Jay
 
A

Alex Martelli

Martin Durkin said:
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and elegance
between that and:

print "\n".join("spam"[::-1]) ...
OK, maybe I'm missing the point here as I'm new to Python. The first
one seems clearer to me. What am I missing?
I think all you are missing is familarity with Python, but I too don't
like one-liners simply for their own sake.

I guess that's it. The first one reads more like a textbook example which
is about where I am at. Is there any speed benefit from the one liner?

The first example reads "excruciatingly low-level" to me: its autor is
thinking in terms of what the machine is doing, mapped into pretty
elementary low-level constructs.

The second example depends first of all on knowledge of extended-slicing
(specifically the fact that x[::-1] is a reversal, because of the
negative -1 "step" aka "stride"). If you don't know about extended
slicing, you're unlikely to just "get it from context", because it uses
a syntax based on punctuation rather than readable words whose meaning
you might guess at. Python has a modest amount of such "punctuation
syntax" -- about the same amount as C but definitely more than Cobol
(where one would typically write "ADD a TO b" to avoid shocking totally
clueless readers with "mysterious punctuation" such as "a + b"...!!!-).
Punctuation is often very concise but not "intrinsically obvious" unless
you've been exposed to it already;-).

If I was targeting total newbies, since extended slicing is something
that they can well wait a while to learn, I'd probably compromise in
favor of "reversed(x)". The "reversed" built-in function does basically
the same job as a [::-1] slicing, but any English speaker can probably
guess what it's doing -- presenting a reversed permutation of its
sequence argument.

So, something like:

for c in reversed(x): print c

is mostly likely how I'd present the solution to the task. Using join
to make a single string is (in this particular case) needlessly
precious, though not really a big deal (and beginners had better learn
about joining pretty early on). But that definitely does not justify
the excruciating, "micromanaged" nature of the first example, which
uselessly belabors the concept of "reversing" to a silly extent.

Python LETS you program at such lowish levels, if you insist, but it
encourages thinking more about your problem and less about the way the
inner gears of the machine will turn in order to produce a solution for
it...! Part of the encouragement is indeed that coding at a higher
level of abstraction tends to make your program faster (an "abstraction
reward" to replace the "abstraction penalty" so common with some other
languages:) -- but clarity and productivity are more important still.


Alex
 
A

Alex Martelli

Jay Loden said:
For what it's worth, with python 2.5 on my Macbook:

Hmmm, doesn't look to me as if it's worth much...:
[jloden@macbook jloden]$ python -m timeit 's = "onomatopoeia"; s =
s.join(s[::-1])'

since what you're doing is...:
s = "onomatopoeia"
s = s.join(s[::-1])
s
'aonomatopoeiaionomatopoeiaeonomatopoeiaoonomatopoeiaponomatopoeiaoonoma
topoeiatonomatopoeiaaonomatopoeiamonomatopoeiaoonomatopoeianonomatopoeia
o'

....which isn't really just reversing the string, but quite a bit more
work!-)


Alex
 
F

Frank Swarbrick

Alex said:
Martin Durkin said:
print "\n".join("spam"[::-1]) ...
OK, maybe I'm missing the point here as I'm new to Python. The first
one seems clearer to me. What am I missing?

I think all you are missing is familarity with Python, but I too don't
like one-liners simply for their own sake.
I guess that's it. The first one reads more like a textbook example which
is about where I am at. Is there any speed benefit from the one liner?

The first example reads "excruciatingly low-level" to me: its autor is
thinking in terms of what the machine is doing, mapped into pretty
elementary low-level constructs.

The second example depends first of all on knowledge of extended-slicing
(specifically the fact that x[::-1] is a reversal, because of the
negative -1 "step" aka "stride"). If you don't know about extended
slicing, you're unlikely to just "get it from context", because it uses
a syntax based on punctuation rather than readable words whose meaning
you might guess at. Python has a modest amount of such "punctuation
syntax" -- about the same amount as C but definitely more than Cobol
(where one would typically write "ADD a TO b" to avoid shocking totally
clueless readers with "mysterious punctuation" such as "a + b"...!!!-).
Punctuation is often very concise but not "intrinsically obvious" unless
you've been exposed to it already;-).

Since you mentioned Cobol I couldn't resist...

move "spam" to spam
Display Function Reverse(spam)

There's also slicing (known in Cobol as "reference modification")
move mystring(5:3) to my-newstring
* moves 3 characters starting with character 5

No "negative" slicing, though it could be simulated with Function
Reverse() and ref.mod.

Frank
 
J

Jay Loden

Alex said:
since what you're doing is...:
s = "onomatopoeia"
s = s.join(s[::-1])
s
'aonomatopoeiaionomatopoeiaeonomatopoeiaoonomatopoeiaponomatopoeiaoonoma
topoeiatonomatopoeiaaonomatopoeiamonomatopoeiaoonomatopoeianonomatopoeia
o'

...which isn't really just reversing the string, but quite a bit more
work!-)

That's what I get for copying and pasting from the post preceding mine and not actually checking it for what it does ;)
 
M

Martin Durkin

(e-mail address removed) (Alex Martelli) wrote in

Martin Durkin said:
def rev(x):
mylist = []
for char in x:
mylist.append(char)
mylist.reverse()
for letter in mylist:
print letter

However, compare the incredible difference in clarity and
elegance between that and:

print "\n".join("spam"[::-1]) ...
OK, maybe I'm missing the point here as I'm new to Python. The
first one seems clearer to me. What am I missing?

I think all you are missing is familarity with Python, but I too
don't like one-liners simply for their own sake.

I guess that's it. The first one reads more like a textbook example
which is about where I am at. Is there any speed benefit from the one
liner?

The first example reads "excruciatingly low-level" to me: its autor is
thinking in terms of what the machine is doing, mapped into pretty
elementary low-level constructs.
sorry you've lost me there.

So, something like:

for c in reversed(x): print c

is mostly likely how I'd present the solution to the task.

This is an interesting point to me. I am just learning Python and I
wonder how I would know that a built in function already exists?
At what point do I stop searching for a ready made solution to a
particular problem and start programming my own function?
Is it just a matter of reading *all* the documentation before I start
coding?
 
P

Paul Rubin

Martin Durkin said:
Is it just a matter of reading *all* the documentation before I start
coding?

It's worth spending an hour or two reading through the library manual,
yes.
 
A

Aahz

(e-mail address removed) (Alex Martelli) wrote in


This is an interesting point to me. I am just learning Python and
I wonder how I would know that a built in function already exists?
At what point do I stop searching for a ready made solution to a
particular problem and start programming my own function? Is it just a
matter of reading *all* the documentation before I start coding?

You should at least know that you can do:

l = list(s)
l.reverse()
for c in l:
print c

This works in all versions of Python back to 1.5.2 IIRC. reversed() is
a moderately new built-in function; I would agree with people who claim
that you should memorize most of the built-in functions (which is
precisely why there is a high barrier to adding more built-in functions).

But certainly if you're using a datatype you should make a point of
reading all its documentation, which would mean you'd know that list()
can convert any iterable type.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top