Home » Coding » c++ » Re: Reverse a String
| Re: Reverse a String [message #17258] |
Fri, 05 October 2007 09:49  |
Jerry Coffin Messages: 135 Registered: August 2007 |
Senior Member |
|
|
In article <pan.2007.10.05.11.34.14.178153@gmail.com>,
geek.arnuld@gmail.com says...
[ ... ]
> PROBLEM: I am not able to reverse the individual strings :-(
Yet! :-)
> #include <iostream>
> #include <string>
> #include <vector>
> #include <algorithm>
> #include <iterator>
>
>
> int main()
> {
> std::vector<std::string> svec;
>
> std::copy( std::istream_iterator<std::string>( std::cin ),
> std::istream_iterator<std::string>(),
> std::back_inserter( svec ) );
Now you have a vector of strings. The next step is to step through the
vector and reverse each one.
> /* prints the vector to standard output */
> std::cout << "\n------------------------------------\n";
> std::copy( svec.begin(), svec.end(),
> std::ostream_iterator<std::string>( std::cout, "\n" ) );
>
> return 0;
> }
[ ... ]
> I tried to use "reverse_copy" in place of 1st std::copy:
The two iterators specifying the input to reverse_copy are required to
be bidirectional iterators, and an istream_iterator isn't a
bidirectional iterator. In C++ 0x, when we get concepts, it'll be
possible to encode requirements like this directly, to allow a much more
informative error message (interestingly, as I understand things, this
problem with error messages was one of the original motivations for the
work that resulted in the concepts proposal).
In any case, it wouldn't really do any good if it did work. You could
(for example) use reverse_copy in place of the _second_ copy quite
easily (vector iterators are random-access iterators, which are a
superset of bidirectional iterators) but it would just copy the strings
in reverse order, leaving each individual string unaffected.
I'd carry out the operation in three steps: read in the strings, then
reverse them, then write them out. You've got the reading and writing
done. The obvious way to reverse them (at least to me) would be a
functor that produces a reversed copy of an individual string, and
std::transform to apply that to the whole vector.
--
Later,
Jerry.
The universe is a figment of its own imagination.
|
|
|
| Re: Reverse a String [message #17278 is a reply to message #17258 ] |
Fri, 05 October 2007 12:50   |
Barry Ding Messages: 32 Registered: September 2007 |
Member |
|
|
arnuld wrote:
>> On Fri, 05 Oct 2007 07:49:47 -0600, Jerry Coffin wrote:
>
>> The two iterators specifying the input to reverse_copy are required to
>> be bidirectional iterators, and an istream_iterator isn't a
>> bidirectional iterator. In C++ 0x, when we get concepts, it'll be
>> possible to encode requirements like this directly, to allow a much more
>> informative error message (interestingly, as I understand things, this
>> problem with error messages was one of the original motivations for the
>> work that resulted in the concepts proposal).
>
> got that :-)
>
>
>> In any case, it wouldn't really do any good if it did work. You could
>> (for example) use reverse_copy in place of the _second_ copy quite
>> easily (vector iterators are random-access iterators, which are a
>> superset of bidirectional iterators) but it would just copy the strings
>> in reverse order, leaving each individual string unaffected.
>
> yes, I knew that and that is why I did not even try to write that one.
>
>
>> I'd carry out the operation in three steps: read in the strings, then
>> reverse them, then write them out. You've got the reading and writing
>> done. The obvious way to reverse them (at least to me) would be a
>> functor that produces a reversed copy of an individual string, and
>> std::transform to apply that to the whole vector.
>
> I have created a function that does that thing and it works :
>
> /* a function to reverse the string */
> void rev_str( std::string& in_str )
string& rev_str
> {
> std::string out_str;
> for( std::string::const_reverse_iterator iter = in_str.rbegin();
> iter != in_str.rend(); ++iter)
> {
> out_str.push_back( *iter );
> }
>
> in_str = out_str;
std::reverse(in_str.begin(), in_str,end()); // do all the work
return in_str;
> }
>
>
>
> then I added this for reversing each string:
>
> std::transform( svec.begin(), svec.end(), svec.begin(), rev_str )
put the return of rev_str to
svec
actually, transform here is not a good idea, as it do call operator=,
though it do check on "this != &rhs".
you can simply write:
for (std::vector<std::string>::iterator iter = svec.begin();
iter != svec.end(); ++iter)
{
std::reverse(iter->begin(), iter->end());
}
>
>
> and it raised a new mysterious error. 3rd argument to std::transform is
> again svec.begin(), as I just want to put the result back into the same
> vector and 4th argument is the function. I have tested the function and it
> reverses a single string without any problem at all.
>
>
> -- arnuld
> http://lispmachine.wordpress.com
>
|
|
| | |
| Re: Reverse a String [message #17327 is a reply to message #17320 ] |
Sat, 06 October 2007 00:32   |
Kai-Uwe Bux Messages: 138 Registered: July 2007 |
Senior Member |
|
|
arnuld wrote:
>> On Fri, 05 Oct 2007 18:57:42 -0600, Jerry Coffin wrote:
>
>> Look through string's ctor's and I'm pretty sure you can find a cleaner
>> way of producing the reversed string.
>
>
> not sure what you mean by saying: string's ctor's but as suggested by
> "Barry" and You, I came up with this:
>
>
>
> /* a function to reverse the string */
> std::string rev_str( std::string& in_str )
> {
> std::string out_str( in_str.rbegin(), in_str.rend() );
>
> return out_str;
> }
That function looks weird: it takes in_str by reference (indicating that it
might want to modify it) Then, however, it never does that. Instead, it
returns the reverted string. Either, you should do:
void revert ( std::string & str ) {
some code;
}
or
std::string reverted_string ( std::string const & in_str ) {
your code from above;
}
>
> int main()
> {
> std::vector<std::string> svec;
>
> /* asks user for input & copied that into a vector of strings */
> std::copy( std::istream_iterator<std::string>( std::cin ),
> std::istream_iterator<std::string>(),
> std::back_inserter( svec ) );
>
> /* reverses each string (which is actually each element of the vector)
> */ std::for_each( svec.begin(), svec.end(), rev_str);
That for_each will do nothing since rev_str does not actually modify the
parameter. You will want to use the version
void revert ( std::string & );
from above.
> /* prints to std. out. */
> std::cout << "\n------------------------------------\n";
> std::copy( svec.begin(), svec.end(),
> std::ostream_iterator<std::string>( std::cout, "\n" ) );
Another idea would be to use transform here with the rev_str() function you
provided.
> return 0;
> }
>
>
> it runs fine.
Yes, but it does not revert anything. :-(
> Is it really necessary to create a function like "rev_str" ?
> Don't we have some Std. Lib. algorithm to do that for us ?
All STL algorithms take ranges by pairs of iterators. If you want to pass a
container, you have to write a small wrapper around the algorithm.
Best
Kai-Uwe Bux
|
|
|
| Re: Reverse a String [message #17331 is a reply to message #17321 ] |
Sat, 06 October 2007 01:02   |
Barry Ding Messages: 32 Registered: September 2007 |
Member |
|
|
arnuld wrote:
>> On Sat, 06 Oct 2007 10:09:01 +0800, Barry wrote:
>
>> The for (...) suggests that you should use for_each rather than transform,
>>
>> as for_each is mutating the InputIterator one by one,
>> while transform means that you reconstruct new object from the
>> InputIterator into OutputIterator, that's why the Operation need a
>> return value.
>
> So using for_each() is more efficient than transform() because transform
> will incur extra run-time cost ?
>
> or you mean
>
> In this particular exercise, using for_each() rather than transform(), is
> a better coding practice ?
>
>
I think both
and from the semantic point of view
transform and for_each are different as I mentioned already.
As in your case, the source and target of /transform/ are the same
(/svec/), so it's more straightforward to say, I'm mutating /svec/
/for_each/
|
|
|
| Re: Reverse a String [message #17353 is a reply to message #17327 ] |
Sat, 06 October 2007 11:33   |
Jerry Coffin Messages: 135 Registered: August 2007 |
Senior Member |
|
|
In article <pan.2007.10.06.14.33.11.37631@gmail.com>,
geek.arnuld@gmail.com says...
> > On Fri, 05 Oct 2007 21:32:28 -0700, Kai-Uwe Bux wrote:
>
> > That function looks weird: it takes in_str by reference (indicating that
> > it might want to modify it) Then, however, it never does that. Instead,
> > it returns the reverted string. Either, you should do:
>
> > ...[SNIP]....
>
> > Yes, but it does not revert anything. :-(
>
> ok, think I have understood it now. for_each() should be used with a
> function that actually reverses a string:
>
> void revert_string( std::string& in_str )
> {
> return std::reverse( in_str.begin(), in_str.end() );
> }
>
>
> whereas, transform(), is good for using a function that returns a copy of
> the input string.
>
> RIGHT ?
Yes -- a copy of the input string after reversing it, of course. I'm not
sure, but he may also have been referring to the fact that "revert" is
the wrong word here -- "revert" refers to returning something to its
previous state, so it really has little or nothing to do with reversing
something.
The reason I didn't recommend using std::for_each (and still don't) is
that for_each is defined as a non-modifying sequence algorithm, which
seems to me means it shouldn't be used to modify the sequence. Others
take it to mean only that for_each itself doesn't modify the sequence,
but what it invokes can do so.
> > All STL algorithms take ranges by pairs of iterators. If you want to
> > pass a container, you have to write a small wrapper around the
> > algorithm.
>
> wrapper around the algorithm ?
>
> I did not understand that, did you mean like what we did here, by
> creating a separate function ?
Yes, I'm pretty sure that's what he meant. It's worth noting that quite
a few people find these small "wrapper" types of functions rather
annoying, and have done various things to eliminate the requirement for
them, at least a large part of the time. There have been a number of
iterations on a proposal to add lambda expressions to C++ 0x. IIRC, the
proposal has been accepted (at least in principle) though there are
probably still details being worked out.
Even now, the Boost library allows you to use lambda expressions for
some situations, so (for example) if you prefer to print the container
out with for_each instead of std::copy, you could do something like:
#include <boost/lambda/lambda.hpp>
using namespace boost::lambda;
// ...
std::for_each(svec.begin(), svec.end(), std::cout << _1 << '\n');
--
Later,
Jerry.
The universe is a figment of its own imagination.
|
|
|
| Re: Reverse a String [message #17384 is a reply to message #17327 ] |
Sun, 07 October 2007 05:36  |
James Kanze Messages: 598 Registered: July 2007 |
Senior Member |
|
|
On Oct 6, 4:33 pm, arnuld <geek.arn...@gmail.com> wrote:
> > On Fri, 05 Oct 2007 21:32:28 -0700, Kai-Uwe Bux wrote:
> > That function looks weird: it takes in_str by reference (indicating that
> > it might want to modify it) Then, however, it never does that. Instead,
> > it returns the reverted string. Either, you should do:
> > ...[SNIP]....
> > Yes, but it does not revert anything. :-(
> ok, think I have understood it now. for_each() should be used with a
> function that actually reverses a string:
> void revert_string( std::string& in_str )
> {
> return std::reverse( in_str.begin(), in_str.end() );
> }
> whereas, transform(), is good for using a function that returns a copy of
> the input string.
> RIGHT ?
No. Transform is used when you want to modify each element of
the sequence, independently of the other elements. Reverse is
used when you want to reverse the order of the elements, without
modifying any of them. Both have there uses, but neither is
what one would call frequent (particularly on strings---I've
never found a real use for either on a string).
> > All STL algorithms take ranges by pairs of iterators. If you want to
> > pass a container, you have to write a small wrapper around the
> > algorithm.
> wrapper around the algorithm ?
Yes.
> I did not understand that, did you mean like what we did here, by
> creating a separate function ?
Exactly.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
|
Goto Forum:
Current Time: Fri May 16 02:44:03 EDT 2008
Total time taken to generate the page: 0.82591 seconds |