Reversing a string

Discussion in 'Python' started by Scott, Jun 27, 2007.

  1. Scott

    Scott Guest

    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:
    [color=blue][color=green][color=darkred]
    >>>mylist = []
    >>>def rev(x):[/color][/color][/color]
                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:
    >>> rev("this is just a test")

    ['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:
    [color=blue][color=green][color=darkred]
    >>>mylist = []
    >>>def rev(x):[/color][/color][/color]
                for char in x:
                    mylist.append(char)
                    mylist.reverse()
                    yield mylist
    
    But even that threw me a curveball:
    >>> rev("this is just a test")

    <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
    Scott, Jun 27, 2007
    #1
    1. Advertising

  2. Scott wrote:
    > 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
    Stefan Behnel, Jun 27, 2007
    #2
    1. Advertising

  3. Scott

    Will Maier Guest

    On Wed, Jun 27, 2007 at 12:53:36PM -0400, Scott wrote:
    > 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.


    >>> def rev(forward):

    ... backward = list(forward)
    ... backward.reverse()
    ... return ''.join(backward)
    >>> rev("spam")

    '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.

    --

    [Will Maier]-----------------[|http://www.lfod.us/]
    Will Maier, Jun 27, 2007
    #3
  4. Scott wrote:

    > 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:
    [color=green][color=darkred]
    >>>>mylist = []
    >>>>def rev(x):[/color][/color]
    >             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:

    >>> x = "abcdefg"
    >>> print "".join(reversed(x))

    gfedcba


    HTH Diez
    Diez B. Roggisch, Jun 27, 2007
    #4
  5. Scott

    Terry Reedy Guest

    "Scott" <> wrote in message
    news:...
    | 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.

    >>> 'this is a test'[::-1]

    'tset a si siht'
    Terry Reedy, Jun 27, 2007
    #5
  6. Scott

    Neil Cerutti Guest

    On 2007-06-27, Scott <> wrote:
    > 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:
    >
    >>>>mylist = []


    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.

    >>>>def rev(x):

    > 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.

    > [/code]


    > 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. ;)

    --
    Neil Cerutti
    This team is one execution away from being a very good basketball team. --Doc
    Rivers
    Neil Cerutti, Jun 27, 2007
    #6
  7. Scott

    ptn Guest


    > >>>>mylist = []

    >
    > 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:

    >>> 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])


    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.
    ptn, Jun 28, 2007
    #7
  8. ptn <> wrote in news:1182997438.541012.54100
    @o61g2000hsh.googlegroups.com:

    >
    >>>> 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?

    Martin
    Martin Durkin, Jul 1, 2007
    #8
  9. Scott

    Duncan Booth Guest

    Martin Durkin <> wrote:

    >>>>> 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.
    Duncan Booth, Jul 1, 2007
    #9
  10. Duncan Booth <> wrote in
    news:Xns996067AFF71DDduncanbooth@127.0.0.1:

    > Martin Durkin <> wrote:
    >
    >>>>>> 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
    Martin Durkin, Jul 1, 2007
    #10
  11. Martin Durkin wrote:
    > Duncan Booth <> wrote in
    > news:Xns996067AFF71DDduncanbooth@127.0.0.1:
    >
    >> Martin Durkin <> wrote:
    >>
    >>>>>>> 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
    Stefan Behnel, Jul 1, 2007
    #11
  12. Scott

    Evan Klitzke Guest

    On 1 Jul 2007 11:09:40 GMT, Martin Durkin <> wrote:
    > Duncan Booth <> wrote in
    > news:Xns996067AFF71DDduncanbooth@127.0.0.1:
    >
    > > Martin Durkin <> wrote:
    > >
    > >>>>>> 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

    --
    Evan Klitzke <>
    Evan Klitzke, Jul 1, 2007
    #12
  13. Scott

    Jay Loden Guest

    Evan Klitzke wrote:
    >
    >> 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
    Jay Loden, Jul 1, 2007
    #13
  14. Martin Durkin <> wrote:
    ...
    > >>>>>> 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
    Alex Martelli, Jul 1, 2007
    #14
  15. Jay Loden <> wrote:
    ...
    > 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
    Alex Martelli, Jul 1, 2007
    #15
  16. Alex Martelli wrote:
    > Martin Durkin <> wrote:
    > ...
    >>>>>>>>> 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
    Frank Swarbrick, Jul 2, 2007
    #16
  17. Scott

    Jay Loden Guest

    Alex Martelli wrote:
    > 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 ;)
    Jay Loden, Jul 2, 2007
    #17
  18. (Alex Martelli) wrote in
    news:1i0kjpx.wjw44j15np22dN%:

    > Martin Durkin <> wrote:
    > ...
    >> >>>>>> 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?
    Martin Durkin, Jul 2, 2007
    #18
  19. Scott

    Paul Rubin Guest

    Martin Durkin <> writes:
    > 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.
    Paul Rubin, Jul 2, 2007
    #19
  20. Scott

    Aahz Guest

    In article <Xns99616C389BA94martinwilliamsdurkin@130.133.1.4>,
    Martin Durkin <> wrote:
    > (Alex Martelli) wrote in
    >news:1i0kjpx.wjw44j15np22dN%:
    >>
    >> 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?


    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.
    --
    Aahz () <*> http://www.pythoncraft.com/

    I support the RKAB
    Aahz, Jul 4, 2007
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. netforce

    reversing a string - newbie question

    netforce, Mar 2, 2004, in forum: C Programming
    Replies:
    9
    Views:
    529
    Old Wolf
    Mar 8, 2004
  2. Albert

    String reversing problem

    Albert, Dec 30, 2005, in forum: C Programming
    Replies:
    46
    Views:
    952
  3. Lindsay
    Replies:
    3
    Views:
    281
    upashu2
    Jul 18, 2005
  4. Kelly B

    Reversing order of words in a given string

    Kelly B, Apr 26, 2007, in forum: C Programming
    Replies:
    2
    Views:
    351
    Kelly B
    Apr 26, 2007
  5. Rubist Rohit
    Replies:
    19
    Views:
    608
    Adam Prescott
    Apr 23, 2011
Loading...

Share This Page