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.
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. | [reply] [d/l] |
|
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 |
| [reply] |
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}
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] |
|
...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}
| [reply] |
|
|
|
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
| [reply] |
|
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.
| [reply] |
|
this was totally useless, thanks for giving up my hopes!
| [reply] |
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)?
| [reply] [d/l] |
|
When at the barrel of a gun...
| [reply] |
|
| [reply] |
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
|
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 ;)
| [reply] [d/l] |
|
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. | [reply] [d/l] |
|
>>> def reverseWords(words):
... return ' '.join(words.split()[::-1])
...
>>> reverseWords(" one two three four ")
'four three two one'
| [reply] [d/l] [select] |
|
[word for word in words.split()] ?
No need for a list comprehensions here. How about this...
def reverseWords(words):
return ' '.join(words.split()[::-1])
| [reply] [d/l] [select] |
|
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
|
open ExtLib;;
open String;;
open List;;
let reverse_words s = join " " (rev (remove_all (nsplit s " ") ""));;
| [reply] [d/l] |
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
]
| [reply] [d/l] |
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.
| [reply] |
|
| [reply] [d/l] [select] |
|
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).
| [reply] |
|
|
|
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.
| [reply] |
|
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".
| [reply] |
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? | [reply] [d/l] |
|
return (reverse(s / " ") - ({ "" })) * " ";
now, that is cool!
| [reply] |
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
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
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 |
| [reply] [d/l] [select] |
|
C:\>perl -e "$,=' ';print reverse qw/ one two three four /;"
four three two one
C:\>
| [reply] [d/l] |
|
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 |
| [reply] |
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
|
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.
| [reply] [d/l] |
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
| [reply] [d/l] [select] |
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.
| [reply] [d/l] |
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=" "))
}
| [reply] [d/l] [select] |
|
| [reply] |
|
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.
| [reply] |
|
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.
|
| [reply] |
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(" ")
| [reply] [d/l] [select] |
|
" one two three four ".split(/ /).reverse().join(" ")
We're building the house of the future together.
| [reply] [d/l] |
|
" one two three four ".split(/ /).reverse().join("|")
which gives you "||||four|three|two|||one||".
| [reply] [d/l] |
|
|
|
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
|
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 "
| [reply] [d/l] [select] |
|
% 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 | [reply] [d/l] [select] |
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;
}
| [reply] [d/l] [select] |
|
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);
}
}
| [reply] [d/l] |
|
#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.
| [reply] [d/l] |
|
| [reply] |
|
You'll need mayonnaise to swallow that.
| [reply] |
|
|
|
#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 "));
}
| [reply] [d/l] |
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
|
#!/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 }]>>"
| [reply] [d/l] |
Re: Five Ways to Reverse a String of Words (ANSI C++ version)
by eyepopslikeamosquito (Archbishop) on Dec 15, 2006 at 08:46 UTC
|
#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;
}
| [reply] [d/l] [select] |
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(' ')
}
| [reply] [d/l] |
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'
| [reply] [d/l] [select] |
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
| [reply] [d/l] |
|
no php yet? no respect! ;)
<?php
$reversed = implode(' ', array_reverse(explode(' ', $str)));
?>
kept it on one line so the perl guys can understand it :)
| [reply] |
|
| [reply] |
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);
}
| [reply] [d/l] |
|
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 )
| [reply] |
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[*]}
| [reply] [d/l] |
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à !
| [reply] |
|
| [reply] [d/l] [select] |
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 :) | [reply] |
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
|
{
for (i=NF ; i > 0 ; i--)
{
printf "%s ", $i
}
}
It should work perfectly the first time! - toma
| [reply] [d/l] |
|
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
}
| [reply] [d/l] |
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}'
| [reply] [d/l] |
|
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
}
| [reply] [d/l] |
|
|