Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)

by eyepopslikeamosquito (Archbishop)
on Dec 12, 2006 at 12:27 UTC ( [id://589260]=perlmeditation: print w/replies, xml ) Need Help??

Recently, the C# programmers at work have been asking job applicants to write a function to reverse a string of words. For example, given an input string of:

" one two three four "
the function should produce:
"four three two one"
That is, the input string reversed word by word, with a single space between each word and with no leading or trailing space. You may assume the input string consists only of alphabetic characters, spaces and tabs.

A popular C# approach goes something like:

private static string reverseWords(string str) { string[] words = Array.FindAll<string>(str.Split( new char[] {' ','\t'}), delegate(string s) { return !String.IsNullOrEmpty(s); }); int i = words.Length - 1; if (i < 0) return String.Empty; StringBuilder sb = new StringBuilder(words[i]); while (--i >= 0) sb.Append(' ').Append(words[i]); return sb.ToString(); }
Though the C# programmers seemed happy with this solution, it's a bit too verbose for my personal taste. When I suggested replacing all the StringBuilder claptrap with:
Array.Reverse(words); return String.Join(" ", words);
they surprised me by saying they preferred the former version because StringBuilder was "faster" (though I couldn't measure any significant difference in running time).

Anyway, this little episode provoked me into solving their little problem in other, er, less verbose languages.

In Perl 5, I whipped up:

sub reverseWords { join ' ', reverse split(' ', shift) }
after a few seconds thought, then pondered a Perl 6 version:
sub reverseWords(Str $s) returns Str { $s.words.reverse.join(' ') }
which resembles a Ruby version:
def reverseWords(s) s.split.reverse.join(' ') end
Finally, this Haskell version:
reverseWords = unwords . reverse . words
may well be the winner of a multi-language golf competition. ;-)

Though one artificial little program proves nothing, at least I've had the satisfaction of demonstrating that this little problem can be easily solved as a one liner in many languages.

Please feel free to improve any of these solutions and/or add a new version in a language of your choice.

References

Acknowledgements: I'd like to thank the friendly folks at Haskell-Cafe for helping me with the Haskell version.

Updated 13-dec: Changed from split to comb in accordance with latest S29, which specifies that split no longer has a default delimiter and advises you instead to comb the words out of the string when splitting on whitespace. Updated 6-oct-2008: Added References section. Updated 10-0ct-2010. Changed comb to words, thanks moritz.

Replies are listed 'Best First'.
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by TimToady (Parson) on Dec 12, 2006 at 18:04 UTC
    You're going to have to try harder if you want Haskell to outgolf Perl 6 here. The following all work in Pugs and are shorter than your Haskell version.
    sub reverseWords ($_) {~reverse .comb} sub reverseWords {~reverse comb @_} my&reverseWords:={~.comb.reverse}
    The first two could even be construed as readable.

      If we're really concerned about golfing to the fewest strokes, you should check out the UCBLogo solution in my post down a few in the discussion. In UCBLogo, the number of (key)strokes needed is zero.

      print substr("Just another Perl hacker", 0, -2);
      - apotheon
      CopyWrite Chad Perrin

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by shmem (Chancellor) on Dec 12, 2006 at 15:09 UTC
    perl5 version without join -
    sub reverseWords { "@{[reverse split' ',shift]}" }

    <update>

    and without split -

    sub reverseWords { "@{[reverse shift=~/\S+/g]}" }

    </update>

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Nice, but you're counting on the special variable $" to have its default value. There's no reason for people not to touch it.

      Either use join, or use

      local $" = ' ';
      in your sub.
        ...yeah, and if I get paranoid I also check whether the stringify and/or (de)ref operators are overloaded, and maybe somebody changed shift and reverse via e.g. schwern's Function::Override... ;-)

        I guess that if somebody changes $" globally, they have a reason, now don't they?

        --shmem

        update: inserted globally

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by philcrow (Priest) on Dec 12, 2006 at 14:03 UTC
    StringBuilder was "faster"
    Are people still suggesting that machine cycles represent the optimal metric of efficiency? Since I started programming in the 1980's people have been making that up hill argument. Isn't an extra $25 toward a better processor a great trade off against me having to maintain the first code sample above.

    In short, to me faster must be measured in my time, not the computer's time. The vacuum tube days of catering to the time demands of the machines should, by now, be long gone.

    Phil

      It also suffers from the sin of premature optimization...

      Do it the easy (and more maintainable) way first, and then find out if it is "too slow". You can always optimize later.

      (or, as you say, buy a faster processor :-)

      -- WARNING: You are logged into reality as root.
        this was totally useless, thanks for giving up my hopes!
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by Arunbear (Prior) on Dec 12, 2006 at 14:28 UTC
    Here is a Lisp version (not much improvement on Perl/Ruby):
    newLISP v.9.0 on Win32 MinGW. > (define (reverseWords s) (join (reverse (parse s)) " ")) (lambda (s) (join (reverse (parse s)) " ")) > (reverseWords " one two three four ") "four three two one"
    Do you ever wonder if the future is Haskell (e.g. you can write Perl6 in it)?
      When at the barrel of a gun...

        or when busy writing an haskell compiler in perl6...;)

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by stvn (Monsignor) on Dec 12, 2006 at 15:53 UTC

    I didn't want Python to feel left out:

    def reverseWords (s): l = s.split(" ") l.reverse() return " ".join(filter(lambda x: x != '', l))
    It has been a long time since I hacked python, so I am sure there is a better way to do this, but then again, there might only be one way ;)

    -stvn

      TMTOWTDI even in Python, these days:

      def reverseWords(words): return ' '.join([word for word in words.split()][::-1])

      I'd probably tweak it a bit in real-world code, though. Generators and list comprehensions make me go cross-eyed sometimes.

      Update: Adjusted the code to match the full goal.

        You don't need [word for word in ...]. That's just the same as map { $_ } ... in perl, an identity op on lists (more or less).

        >>> def reverseWords(words): ... return ' '.join(words.split()[::-1]) ... >>> reverseWords(" one two three four ") 'four three two one'
        [word for word in words.split()] ?
        No need for a list comprehensions here. How about this...
        def reverseWords(words): return ' '.join(words.split()[::-1])
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by stvn (Monsignor) on Dec 12, 2006 at 14:55 UTC

    Here is the OCaml version (utilizing ExtLib):

    open ExtLib;; open String;; open List;; let reverse_words s = join " " (rev (remove_all (nsplit s " ") ""));;

    -stvn
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by webfiend (Vicar) on Dec 12, 2006 at 18:26 UTC

    Hey, as long as we're goofing with languages, here is a version in REBOL.

    reverse-words: func [ words ] [ return form reverse parse words none ]
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell) (pike?)
by jettero (Monsignor) on Dec 12, 2006 at 20:24 UTC
    How is pike not on here yet?
    string reverseWords(string s) { return (reverse(s / " ") - ({ "" })) * " "; }

    Have you guys seen the pleac project?

      return (reverse(s / " ") - ({ "" })) * " "; 
      

      now, that is cool!

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by ambrus (Abbot) on Dec 12, 2006 at 23:06 UTC

    The J language isn't particularly strong in string manipulation. You can get an easy solution this way:

    reverseWords =: (,' '&,)&:>/@:|.@:;: reverseWords ' one two three four ' four three two one
    but it sort of feels like cheating because of the use of the ;: verb which breaks a string to J tokens.

    A solution without this cheating is (I have replaced the tab character with a hat for legibility):

    reverseWord1 =: [:(,' '&,)&:>/@:|.@:-.&a:e.&' ^'<@}.;.1] reverseWord1 ' one two three^four ' four three two one
    Another solution is:
    reverseWord2 =: [:}.@;@|.e.&' ^'<@(' '&,@}.`(0$])@.(2>#));.1] reverseWord2 ' one two three^four ' four three two one

      Incidentally, reverseWords =: |.&.;: works as well.

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by apotheon (Deacon) on Dec 13, 2006 at 01:48 UTC

    This task gets absurdly easy in UCBLogo (a Logo dialect that is, in effect, an M-expression dialect of Lisp complete with macros). It is, in fact, so easy as to be almost meaningless in the context of UCBLogo. You don't have to create the procedure (aka function/subroutine) at all because it already exists in the form of the language primitive procedure reverse.

    The reason it works that way is pretty simple: in UCBLogo, the way one represents a "string" made up of a number of words is as a bracketed list, what in UCBLogo parlance is the list, or sentence, data type. The reverse procedure operates on lists, same as the Perl function of the same name, but the fact that the list data type in UCBLogo is in effect its string data type eliminates a middleman.

    Thus, no procedure definition is needed, and using it looks like this:

    reverse [  one   two three four    ]

    The output looks like this:

    [four three two one]

    There are some definite advantages to treating all data as lists (the other type of lists in UCBLogo being known as words).

    print substr("Just another Perl hacker", 0, -2);
    - apotheon
    CopyWrite Chad Perrin

      And by the same token;
      C:\>perl -e "$,=' ';print reverse qw/ one two three four /;" four three two one C:\>

       

        Absolutely. You can do list-oriented programming in Perl as well. The problem that arises is that while doing list-oriented programming you lose the ability to do certain text manipulations without breaking the list-oriented style. For instance, you run afoul of problems with regular expressions over a string if you represent the string as an array. Similarly, you must convert to a list when you read strings in from external sources.

        There are many things that Perl does better for text processing than UCBLogo, but I think UCBLogo wins on this one score.

        print substr("Just another Perl hacker", 0, -2);
        - apotheon
        CopyWrite Chad Perrin

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by fergal (Chaplain) on Dec 12, 2006 at 13:49 UTC
    StringBuilder was "faster"

    Apparently this can be true but only in certain circumstances. Really it just sounds like your coworkers read it somewhere and believed it.

      One may do this with a logarithmic number of concatenations, though (instead of linear). I don't see a feasible way to do such a thing with StringBuilder,

      That may make concatenation faster than StringBuilder even in the case of a large number of strings.

      I wonder how Perl's join actually works.

        How do you concatenate n strings in O(log n)? Every string will have to be concatenated to something least once, so it's not obvious to me how it could ever be less than O(n).

        Concatenating in pairs and then concatenating the results etc adds up to O(n).

      It’s not about it being faster but more efficient. Each time you concatenate strings you cause new copies of the original string variable to be made.

        So since faster is a relatively objective term and "efficient" depends on what you're trying to minimise usage of, arguing that it's more efficient without further details doesn't really work.

        Of course you could define efficiency differently. Maybe you're trying to minimise peak memory consumption, network utilisation, coding time or whatever but you haven't said that's what you want.

        In this case, why do you want to avoid the string copying? Because each copy takes time. Unless the final string is long enough to start filling main memory, memory usage is not an issue and that leaves only speed. So as far as I can see, except for special cases, when discussing string concat the only useful definition of "more efficient" == "faster".

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by BrowserUk (Patriarch) on Dec 12, 2006 at 15:48 UTC

    sub reverseWords{local$_=reverse pop; s[\b(\S+)\b]{reverse $1}ge; $_ }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by moklevat (Priest) on Dec 12, 2006 at 19:57 UTC
    Fun thread! Here it is in R :
    reverseWords <- function(words) { return( sort( words, decreasing=TRUE)) }

    Updated:

    Fixed now. Thanks to jdporter for catching a goof.

    reverseWords <- function(words) { return( paste( rev( unlist( strsplit( words, split=" "))), sep=" ", +collapse=" ")) }

      I don't know R... but, to my naive eye, that looks like it does neither the split nor the join. Is R one of those shell-like languages which implement lists as strings?

      We're building the house of the future together.
        Dang it. No, it's not.

        This isn't a problem with R, it is a problem with me not thinking. Not only did I forget the split/join, the sort function I originally used only worked because my test case happened to be in alphabetical order. I have updated the original post with functioning code.

        My apologies to all of you who incorporated the broken code into your mission-critical systems.

        Is R one of those shell-like languages which implement lists as strings?

        No.

        I don't know R... but, to my naive eye, that looks like it does neither the split nor the join.

        You're right. The function posted above fails because it doesn't do the split or the join. R is lovely for statistics, but it's clumsy with text, despite efforts to implement Perl-like regex capabilities.

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by swampyankee (Parson) on Dec 13, 2006 at 16:07 UTC

    Just so users of more traditional languages don't get left out:

    IMPLICIT NONE ! Fortran's equivalent to use strict;use warnings CHARACTER(len=*),PARAMETER,DIMENSION(4) :: in = (/' one', 'two', 'thr +ee ', 'four'/) DO n = SIZE(n),2, -1;WRITE(*,'(a,",",1x)',advance = 'no') TRIM(ADJUSTL +(in(n)));ENDDO WRITE(*,'(a)') TRIM(ADJUSTL(in(1))

    OOPS! forgot to split it. I've written a split routine in Fortran (without, alas, regex support). It's actually quite easy, especially since, in Fortran, storage for everything in an argument list is responsibility of the caller. My next feat will be to include regex support....

    emc

    At that time [1909] the chief engineer was almost always the chief test pilot as well. That had the fortunate result of eliminating poor engineering early in aviation.

    —Igor Sikorsky, reported in AOPA Pilot magazine February 2003.
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by YuckFoo (Abbot) on Dec 13, 2006 at 18:42 UTC
    #!/usr/local/bin/lua function reverseWords(str) list = {} for word in string.gfind(str, "(%w+)") do table.insert(list, 1, word) end return (table.concat(list, " ")) end print(reverseWords(" one two three four "))
    or maybe
    #!/usr/local/bin/lua function reverseWords(str) list = {} string.gsub(str, "(%w+)", function(word) table.insert(list, 1, word) end) return (table.concat(list, " ")) end print(reverseWords(" one two three four "))
    YuckFoo
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl6, Ruby, Haskell)
by stvn (Monsignor) on Dec 12, 2006 at 15:27 UTC

    Because I really have come to hate for loops, here is one in Javascript which uses a fixed point combinator to do the looping and filtering of the list.

    function (orig, i, acc) { if (i > orig.length) return acc; if (orig[i] != "") acc[acc.length] = orig[i]; return arguments.callee(orig, (i + 1), acc); }(" one two three four ".split(" ").reverse(), 0, []).join(" ")

    -stvn

      Huh?

      " one two three four ".split(/ /).reverse().join(" ")
      We're building the house of the future together.

        Actually that doesn't work correctly in FF or Safari on OS X. It still has several empty strings filling up the array. They become more evident if you do this:

        " one two three four ".split(/ /).reverse().join("|")
        which gives you "||||four|three|two|||one||".

        -stvn
Re: Five Ways to Reverse a String of Words (ANSI C version)
by eyepopslikeamosquito (Archbishop) on Dec 15, 2006 at 08:36 UTC

    Here's a version in plain ANSI C. Yikes, that looks bad compared to the one liners. :-)

    #include <stdio.h> #include <stdlib.h> #include <string.h> /* reverse a string in place, return str */ static char* reverse(char* str) { char* left = str; char* right = left + strlen(str) - 1; char tmp; while (left < right) { tmp = *left; *left++ = *right; *right-- = tmp; } return str; } static int reverseWords( const char* instr, /* in: string of words */ char* outstr) /* out: reversed words */ /* (caller must ensure big enough) */ { char* p; char* buf; *outstr = '\0'; if ((buf = (char*)malloc(strlen(instr)+1)) == NULL) { fprintf(stderr, "oops, out of memory\n"); return -1; } strcpy(buf, instr); reverse(buf); if ((p = strtok(buf, " \t")) == NULL) { free(buf); return 0; } strcpy(outstr, reverse(p)); outstr += strlen(p); while ((p = strtok(NULL, " \t")) != NULL) { *outstr++ = ' '; strcpy(outstr, reverse(p)); outstr += strlen(p); } free(buf); return 0; } int main() { char instr[256]; char outstr[256]; strcpy(instr, " one two \t three four "); reverseWords(instr, outstr); printf("in='%s' out='%s'\n", instr, outstr); return 0; }

    Updated 17-Dec: Added improved version without the ugly malloc/strtok below:

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> static const char* get_next_word(const char* pstart, const char* p, si +ze_t* len) { const char* pend; while (p >= pstart && isspace(*p)) --p; if (p < pstart) return NULL; pend = p-- + 1; while (p >= pstart && !isspace(*p)) --p; *len = pend - ++p; return p; } static void reverseWords( const char* instr, /* in: string of words */ char* outstr) /* out: reversed words */ /* (caller must ensure big enough) */ { const char* p = instr + strlen(instr) - 1; size_t len; if ((p = get_next_word(instr, p, &len)) == NULL) { *outstr = '\0'; return; } memcpy(outstr, p, len); outstr += len; while ((p = get_next_word(instr, --p, &len)) != NULL) { *outstr++ = ' '; memcpy(outstr, p, len); outstr += len; } *outstr = '\0'; return; } int main() { char instr[256]; char outstr[256]; strcpy(instr, " one two \t three four "); reverseWords(instr, outstr); printf("in='%s' out='%s'\n", instr, outstr); return 0; }

      A reverse-words-in-place C version:
      #include <stdio.h> #include <stdlib.h> char * readlinef(FILE *stream) { int buffer_len = 0; int len = 0; char *buffer; while (1) { int c = fgetc(stream); switch (c) { case '\n': if (!len) continue; case EOF: if (buffer) buffer[len] = '\0'; return buffer; default: if (len >= buffer_len) { buffer_len = buffer_len * 2 + 100; buffer = (char *)realloc(buffer, buffer_len + 1); } buffer[len++] = c; } } } void reverse(char *start, char *end) { while (start < --end) { char tmp = *end; *end = *start; *(start++) = tmp; } } char * skip_spaces(char *p) { while (isspace(*p)) p++; return p; } char * skip_word(char *p) { while (*p && !isspace(*p)) p++; return p; } int main(int argc, char *argv[]) { char *line; while (line = readlinef(stdin)) { char *start = line; while (1) { char *word_start = skip_spaces(start); char *word_end = skip_word(word_start); if (word_start == word_end) { if (start != line) start--; break; } reverse(start, word_end); start += word_end - word_start; if (*start == '\0') break; start++; } reverse(line, start); *start = '\0'; fprintf(stdout, "%s\n", line); free(line); } }

        My try inspired by bitingduck's triple reverse:

        #include <stdio.h> #include <string.h> void reverse( char*p, int n ) { char c, *e = p+n-1; n /= 2; while( n-- ) c = *p, *p++ = *e, *e-- = c; } char *reverseWords( char*line ) { int len = (int)strlen( line ); char *p = line, *p1 = line, *e = line+len; reverse( line, len ); while( p <= e ) { if( *p == 32 || *p == 0 ) { reverse( p1, (int)( p - p1) ); p1 = p+1; } ++p; } return line; } int main( int argc, char **argv ) { char line[ 1024 ]; printf( "%s\n", reverseWords( gets_s( line, 1024 ) ) ); return 0; }

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
      supper !
        You'll need mayonnaise to swallow that.

         

      A somewhat condensed, C99 version:

      #include <stdio.h> #include <ctype.h> #include <string.h> char *str_rwords(char *s) { int n = strlen(s); char t[n], *e = t + n, *d = e, *s0; do { for (s0 = s; *s && isalpha(*s); s++); if ((n = s - s0)) { if (d != e) *--d = ' '; d = memcpy(d - n, s0, n); } } while (*s++); return strndup(d, e - d); } int main(void) { puts(str_rwords(" one two \t three four ")); }

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by parv (Parson) on Dec 14, 2006 at 01:33 UTC

    My dutiful contribution in languages not listed in OP; first Rexx ...

    say word_reverse( " one two three four " ) exit word_reverse: procedure parse arg string new = '' do w = 1 to words( string ) new = word( string , w ) new end return strip( new , 'T' )

    ... and similar in (a)sh (as found on FreeBSD 6.x) ...

    word_reverse() { local string="$1" new='' for s in $string do new="$s $new" done printf "%s" "${new%% }" } word_reverse " one two three four "

      not too sure about ash but you get less chars with:

       print "${new% }"

      another way showing off some aspects of modern shells but still a bit longish...

      % stephan@labaule (/home/stephan) % % cat rev.sh #!/bin/ksh93 function rev { nameref s=$1; typeset a=( $s ); integer n=${#a[*]} i; s=; n=n-1 for i in {$n..0}; do s+="${a[i]} "; done; s=${s%?} } s=" one two three four " rev s print "[$s]" % stephan@labaule (/home/stephan) % % ksh93 rev.sh [four three two one]
      enjoy ;) --steph
Re: Five Ways to Reverse a String of Words (ANSI C++ version)
by eyepopslikeamosquito (Archbishop) on Dec 15, 2006 at 08:46 UTC

    Here are two versions in plain ANSI C++.

    #include <string> #include <sstream> #include <iostream> using namespace std; static string reverseWords(string const& instr) { istringstream iss(instr); string outstr; string word; iss >> outstr; while (iss >> word) outstr = word + ' ' + outstr; return outstr; } int main() { string s = " one two \t three four "; string sret = reverseWords(s); cout << "in='" << s << "' " << "out='" << sret << "'" << endl; return 0; }
    and
    #include <string> #include <sstream> #include <iostream> #include <deque> #include <algorithm> using namespace std; static string reverseWords(string const& instr) { istringstream iss(instr); deque<string> dqs; copy(istream_iterator<string>(iss), istream_iterator<string>(), front_inserter(dqs)); if (dqs.empty()) return ""; ostringstream oss; copy(dqs.begin(), --dqs.end(), ostream_iterator<string>(oss, " ")) +; oss << dqs.back(); return oss.str(); // ... or build string directly instead of using ostringstream // string outstr(dqs.front()); // for (deque<string>::const_iterator i = ++dqs.begin(); i != dqs. +end(); ++i) // outstr += ' ' + *i; // return outstr; } int main() { string s = " one two \t three four "; string sret = reverseWords(s); cout << "in='" << s << "' " << "out='" << sret << "'" << endl; return 0; }

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by AltBlue (Chaplain) on Dec 14, 2006 at 15:28 UTC
    A Tcl version:
    #!/usr/bin/tclsh proc reversewords {str} { proc rev {a b} {return 1} return [join [lsort -command rev [regexp -all -inline -- {\S+} $st +r]]] } puts "<<[reversewords { one two three four }]>>"
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by IulianU (Novice) on Dec 14, 2006 at 23:04 UTC
    Still in Java-dom, here's a version in Groovy:
    def reverseWords( str ) { str.split('\\s+'). findAll {it.length() > 0}. reverse().join(' ') }
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by ambrus (Abbot) on Sep 09, 2008 at 15:46 UTC

    This thread has no sed solution yet?

    The following program reads a single line, and gives its words in reverse.

    sed 's/^/@/;:;s/\(.*@\)[ \t]*\([^ \t][^ \t]*\)/\2 \1/;t;s/ *@.*//;q'

    (This works in GNU sed. If you use another sed, you may need to change the semicolons to new lines, and the \t escapes to real tab characters.)

    This really breaks if the input contains an at-sign. If you need such inputs, change the at-sign to some other character that doesn't occurr in the input, or use the following more complicated snippet.

    sed 's/@/@a/g;s/^/@s/;:;s/\(.*@s\)[ \t]*\([^ \t][^ \t]*\)/\2 \1/;t;s/ +*@s.*//;s/@a/@/g;q'
Re: Five Ways to Reverse a String of Words (..., Oz)
by diotalevi (Canon) on Jan 07, 2007 at 19:41 UTC

    For giggles I tried writing this in Oz. The ReverseWords function could have been written without all the intermediate variables but it would have suffered in readability so I didn't. It's also a complete program with loading the appropriate libraries, etc.

    functor import Application System String at 'x-oz://system/String.ozf' define fun {IsntNil X} case X of nil then false else true end end fun {ReverseWords In Split} local Tokens FilteredTokens Reversed Str in Tokens = {String.split In Split} FilteredTokens = {List.filter Tokens IsntNil} Reversed = {List.reverse FilteredTokens} Str = {String.join Reversed Split} {String.toAtom Str} end end in {System.print {ReverseWords " one two three four " " "}} {Application.exit 0} end

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      no php yet? no respect! ;)

      <?php
      $reversed = implode(' ', array_reverse(explode(' ', $str)));
      ?>

      kept it on one line so the perl guys can understand it :)
        php is the bomb
Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by Hue-Bond (Priest) on Sep 09, 2008 at 21:55 UTC

    No bash solution yet, so here it goes (pure bash, no external binaries):

    STR=" one two three four " ARR=($STR) LEN=${#ARR[*]} LAST=$(($LEN-1)) ARR2=() I=$LAST while [[ $I -ge 0 ]]; do ARR2[ ${#ARR2[*]} ]=${ARR[$I]} ## push I=$(($I-1)) done echo ${ARR2[*]}

    --
    David Serrano

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell) (a Java 1.5 version)
by IulianU (Novice) on Dec 14, 2006 at 22:08 UTC
    public static String reverseWords( String src ) { List<String> pcs = Arrays.asList( src.split("\\s+") ); Collections.reverse( pcs ); StringBuffer result = new StringBuffer(); for( String pc : pcs ) result.append(" ").append(pc); return result.substring(1); }
      Of course the above is broken :) It appends a trailing empty space. There are two ways to fix it: 1) return result.toString().trim(); instead of return result.substring(1); 2) filter out zero-length pieces in the for loop with something like if( pc.length() == 0 )
Smalltalk - Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by carcassonne (Pilgrim) on Dec 15, 2006 at 02:31 UTC
    Here goes in Smalltalk:

    #('one' 'two' 'three' 'four') reversed

    Do a print-It in the workspace and it gives:

    #('four' 'three' 'two' 'one')

    You put your things in an OrderedCollection and this collection has a reversed message that can be sent to it. Voilà !

      That utterly fails the requirement, which is to take a string like "one two three four" and return a string like "four three two one".

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by exussum0 (Vicar) on Dec 13, 2006 at 13:09 UTC
    Side conversation:

    The collection of symbols in an alphabet is a string. Strings have a concatonation function, that results in another string "abcd" + "e" = "abcde".

    Regarding the title title, a set of strings may be more accurate.

    Just side thoughts and mincing words :)

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by toma (Vicar) on Dec 19, 2006 at 08:07 UTC
    My awk is rusty!
    { for (i=NF ; i > 0 ; i--) { printf "%s ", $i } }
    It should work perfectly the first time! - toma

      My awk is very rusty too. Unfortunately, your version emits a trailing space, which violates the spec. I've remedied that below and done it in the form of a function so that it can be more easily compared with the other languages.

      # File : revwords.awk # Run with : awk -f revwords.awk </dev/null END { print reverseWords(" one two three four ") } function reverseWords(s) { if ((i = split(s, words)) == 0) return "" sret = words[i] while (--i > 0) sret = sret " " words[i] return sret }

Re: Five Ways to Reverse a String of Words (C#, Perl 5, Perl 6, Ruby, Haskell)
by Anonymous Monk on Feb 22, 2008 at 06:14 UTC
    A compacted awk one liner...
    echo " one two three four " | awk '{n=split($0,A);S=A[n];{for(i= +n-1;i>0;i--)S=S" "A[i]}}END{print S}'
      Here's another awk solution (different strategy, and slightly shorter when compacted - Update: this reverses every line, and if your's did the same, i.e, without the END block, it would still be shorter than this...oh well):
      #!/bin/awk -f { for (i=1; i<=NF/2; i++) { t=$i $i = $(NF-i+1) $(NF-i+1)=t } print }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://589260]
Approved by Corion
Front-paged by grinder
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (6)
As of 2024-03-28 21:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found