copying elements from a <list> to <deque>

A

arnuld

It works fine. any advice on making it better or if I can
improve my C++ coding skills:

/* C++ Primer - 4/e
*
* Chapter 9 - Sequential Containers
* exercise 9.18 - STATEMENT
* Write a program to copy elements from a list of "ints"
* to 2 "deques". The list elements that are even should go into one deque
* and even elements should go into 2nd deque.
*
*/

#include <iostream>
#include <list>
#include <deque>
#include <algorithm>
#include <iterator>

int main()
{
std::cout << "enter some integers: ";
std::list<int> ilist;
/* copy elements from std::cin into ilist */
std::copy( (std::istream_iterator<int>( std::cin )),
(std::istream_iterator<int>()),
std::back_inserter( ilist ) );

std::deque<int> deque_of_evens;
std::deque<int> deque_of_odds;
/* copy even elements into 1 deque and odds into the other */
for( std::list<int>::const_iterator iter = ilist.begin();
iter != ilist.end();
++iter)
{
if( *iter % 2 == 0 )
{
deque_of_evens.push_back( *iter );
}
else
{
deque_of_odds.push_back( *iter );
}
}



std::cout << "\n Printing Deque of Even Integers: ";
std::copy( deque_of_evens.begin(),
deque_of_evens.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );

std::cout << "\n\n Printing Deque of Odd Integers: ";
std::copy( deque_of_odds.begin(),
deque_of_odds.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );

std::cout << std::endl;

return 0;
}
 
G

Guest

It works fine. any advice on making it better or if I can
improve my C++ coding skills:

/* C++ Primer - 4/e
*
* Chapter 9 - Sequential Containers
* exercise 9.18 - STATEMENT
* Write a program to copy elements from a list of "ints"
* to 2 "deques". The list elements that are even should go into one deque
* and even elements should go into 2nd deque.
*
*/

#include <iostream>
#include <list>
#include <deque>
#include <algorithm>
#include <iterator>

int main()
{
std::cout << "enter some integers: ";
std::list<int> ilist;
/* copy elements from std::cin into ilist */
std::copy( (std::istream_iterator<int>( std::cin )),
(std::istream_iterator<int>()),
std::back_inserter( ilist ) );

std::deque<int> deque_of_evens;
std::deque<int> deque_of_odds;
/* copy even elements into 1 deque and odds into the other */
for( std::list<int>::const_iterator iter = ilist.begin();
iter != ilist.end();
++iter)
{
if( *iter % 2 == 0 )
{
deque_of_evens.push_back( *iter );
}
else
{
deque_of_odds.push_back( *iter );
}
}



std::cout << "\n Printing Deque of Even Integers: ";
std::copy( deque_of_evens.begin(),
deque_of_evens.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );

std::cout << "\n\n Printing Deque of Odd Integers: ";
std::copy( deque_of_odds.begin(),
deque_of_odds.end(),
std::eek:stream_iterator<int>( std::cout, " " ) );

std::cout << std::endl;

return 0;
}

You should research the (IMO badly named) remove_copy_if algorithm and
create a predicate to determine if the element is even or not.
 
K

Kai-Uwe Bux

Erik said:
You should research the (IMO badly named) remove_copy_if algorithm and
create a predicate to determine if the element is even or not.

And: you should implement the missing (sic!) copy_if algorithm and use the
same predicate for the other copy job.


Best

Kai-Uwe Bux
 
J

James Kanze

You might replace the if with:

(*iter % 2 == 0 ? deque_of_evens :
deque_of_odds).push_back( *iter ) ;

Opinions about this vary; I tend not to use ?: very much for
lvalues, but in this case, it does draw attention to the fact
that *all* of the elements end up in one of the two deques.
And: you should implement the missing (sic!) copy_if algorithm
and use the same predicate for the other copy job.

I'm not sure that I agree with either of these recommendations.
Both smack of obfuscation, and forcing things just to use a
standard (or non-standard, in the case of copy_if) algorithm.
For a more experienced programmer, I might consider a
boost::filter_iterator, e.g.:

std::deque< int > evens(
boost::make_filter_iterator< IsEven >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsEven >( ilist.end(),
ilist.end() ) ) ;
std::deque< int > odds(
boost::make_filter_iterator< IsOdd >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsOdd >( ilist.end(),
ilist.end() ) ) ;

This allows correct initialization; it would even allow making
evens and odds const. But it still requires moving the test out
of the loop, and even out of the function. And I'm pretty sure
that it's not the intent of the exercise.
 
A

arnuld

You might replace the if with:

(*iter % 2 == 0 ? deque_of_evens :
deque_of_odds).push_back( *iter ) ;

Opinions about this vary; I tend not to use ?: very much for
lvalues, but in this case, it does draw attention to the fact
that *all* of the elements end up in one of the two deques.

that's nice James (as for as my exercise is concerned ). I have
used that construct, it make my solution look clean :)
 
K

Kai-Uwe Bux

James said:
You might replace the if with:

(*iter % 2 == 0 ? deque_of_evens :
deque_of_odds).push_back( *iter ) ;

Opinions about this vary; I tend not to use ?: very much for
lvalues, but in this case, it does draw attention to the fact
that *all* of the elements end up in one of the two deques.



I'm not sure that I agree with either of these recommendations.
Both smack of obfuscation, and forcing things just to use a
standard (or non-standard, in the case of copy_if) algorithm.

I have a great deal of sympathy for that sentiment. Functors tend to move
code from the place where you would like to see it to some other place.
That is generally not so good.

For a more experienced programmer, I might consider a
boost::filter_iterator, e.g.:

std::deque< int > evens(
boost::make_filter_iterator< IsEven >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsEven >( ilist.end(),
ilist.end() ) ) ;
std::deque< int > odds(
boost::make_filter_iterator< IsOdd >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsOdd >( ilist.end(),
ilist.end() ) ) ;

This allows correct initialization; it would even allow making
evens and odds const. But it still requires moving the test out
of the loop, and even out of the function.
[snip]

In a case like this, I like lambda:

std::remove_copy_if( ilist.begin(), ilist.end(),
std::back_inserter( deque_of_evens ),
_1 % 2 != 0 );

std::remove_copy_if( ilist.begin(), ilist.end(),
std::back_inserter( deque_of_odds ),
_1 % 2 == 0 );

(yet, I would prefer copy_if :)

I agree, though, that cases where lambda is this concise are rare. But
compared to using std::binder..., std::modulus, ... lambda is great.


Best

Kai-Uwe Bux
 
A

arnuld

In a case like this, I like lambda:

std::remove_copy_if( ilist.begin(), ilist.end(),
std::back_inserter( deque_of_evens ),
_1 % 2 != 0 );

std::remove_copy_if( ilist.begin(), ilist.end(),
std::back_inserter( deque_of_odds ),
_1 % 2 == 0 );

ok, that's nice :)

and i did not get that _1 %2, I know it checks for even and odd
numbers but what exactly that "underscore 1" means: _1 %2
 
K

Kai-Uwe Bux

arnuld said:
ok, that's nice :)

and i did not get that _1 %2, I know it checks for even and odd
numbers but what exactly that "underscore 1" means: _1 %2


That's the magic of expression templates. If you are interested, you can
have a look at my posting

http://groups.google.com/group/comp.lang.c++/browse_frm/thread/739246bc9aef054e/09422ea883a2b151

where I explain how one can about implementing something like that. Be
warned, however: it takes about 600 lines of code (and 300 lines of
comments) to make that _1 work (and that is just a proof of concept!).

Luckily, it already has been done and is in boost.


Best

Kai-Uwe Bux
 
A

arnuld

I'm not sure that I agree with either of these recommendations.
Both smack of obfuscation, and forcing things just to use a
standard (or non-standard, in the case of copy_if) algorithm.
For a more experienced programmer, I might consider a
boost::filter_iterator, e.g.:

std::deque< int > evens(
boost::make_filter_iterator< IsEven >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsEven >( ilist.end(),
ilist.end() ) ) ;
std::deque< int > odds(
boost::make_filter_iterator< IsOdd >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsOdd >( ilist.end(),
ilist.end() ) ) ;

This allows correct initialization; it would even allow making
evens and odds const. But it still requires moving the test out
of the loop, and even out of the function. And I'm pretty sure
that it's not the intent of the exercise.

I am trying this but can not copile my program with that without
errors. I am using remove_copy_if as suggested by Kai-Uwe Bux
(remember the _1 ;-)

but still I am interested in this use of boost library. I have copied
the code you wrote but then I am not able to get what to do to
make use of this make_filter_iterator.

any explanation ?
 
J

James Kanze

James Kanze wrote:

[...]
I have a great deal of sympathy for that sentiment. Functors
tend to move code from the place where you would like to see
it to some other place. That is generally not so good.

It depends. If you can supply a good, explicit name for the
function, and it is a "pure" function, not depending on any
local variables, it's not that bad. If you can reasonably
expect to use the function elsewhere, it's even good. I'd say
that his case meets the first criteron, but not really the
second. So it's not too bad, but I still prefer the test in an
explicit loop. (There's also the question of how much you're
throwing at the OP at a time. He IS working his way through a
tutorial text, and shouldn't be expected to handle everything at
once. Each thing in its time.)
For a more experienced programmer, I might consider a
boost::filter_iterator, e.g.:
std::deque< int > evens(
boost::make_filter_iterator< IsEven >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsEven >( ilist.end(),
ilist.end() ) ) ;
std::deque< int > odds(
boost::make_filter_iterator< IsOdd >( ilist.begin(),
ilist.end() ),
boost::make_filter_iterator< IsOdd >( ilist.end(),
ilist.end() ) ) ;
This allows correct initialization; it would even allow
making evens and odds const. But it still requires moving
the test out of the loop, and even out of the function.

In a case like this, I like lambda:
std::remove_copy_if( ilist.begin(), ilist.end(),
std::back_inserter( deque_of_evens ),
_1 % 2 != 0 );
std::remove_copy_if( ilist.begin(), ilist.end(),
std::back_inserter( deque_of_odds ),
_1 % 2 == 0 );
(yet, I would prefer copy_if :)
I agree, though, that cases where lambda is this concise are
rare. But compared to using std::binder..., std::modulus, ...
lambda is great.

If we had a real lambda, it would be great (although as you
point out, in this particular case, boost::lambda works like a
real lambda). Ideally, even, we'd have a lambda which resolved
to a class which could be used to instantiate a template like
boost::make_filter_iterator, so I could replace IsEven and IsOdd
in my example.
 
J

James Kanze

I am trying this but can not copile my program with that without
errors. I am using remove_copy_if as suggested by Kai-Uwe Bux
(remember the _1 ;-)

Do you have Boost correctly installed? Are you including all of
the necessary Boost header files, and passing the necessary
options to the compiler so that it finds them (and the Boost
library, although I don't think either Kai-Uwe's suggestion or
mine actually require linking against the library).
but still I am interested in this use of boost library. I have
copied the code you wrote but then I am not able to get what
to do to make use of this make_filter_iterator.
any explanation ?

The real explanation is that you're jumping too far ahead of
where you are in the learning cycle. Learn the basics first;
there's time enough for Boost later.

Other than that, of course, you have to ensure that Boost is
correctly installed, that the compiler is passed all of the
necessary options, etc. (Under Unix, for example, you'll need
at least an additional -I option, and perhaps also an additional
-l. With VC++, that's a /I option and an additional library to
link against.) But seriously: I prefixed my suggestion with
"For a more experienced programmer". I did so for a reason.
Don't worry about it yet.
 
A

arnuld

Do you have Boost correctly installed?
yes.

Are you including all of
the necessary Boost header files, and passing the necessary
options to the compiler so that it finds them (and the Boost
library, although I don't think either Kai-Uwe's suggestion or
mine actually require linking against the library).

The real explanation is that you're jumping too far ahead of
where you are in the learning cycle. Learn the basics first;
there's time enough for Boost later.
.....[SNIP]....

But seriously: I prefixed my suggestion with
"For a more experienced programmer". I did so for a reason.
Don't worry about it yet.

Ok, I understood :) for now, I will just use <algorithm>


-- arnuld
http://lispmachine.wordpress.com
 
G

Guest

don't know, I just used "#include <boost>" and GCC complained then.

I'm not a boost expert, but including <boost> is probably not the right
way, you should include <boost/iterator/filter_iterator.hpp> and you
might need to include some other headers too.
 
J

James Kanze

[...]
don't know, I just used "#include <boost>" and GCC complained then.

That is surely wrong. But one of the really big weaknesses of
the Boost documentation is that they don't tell you what headers
you need. (Probably <boost/iterator.hpp>, here. Or perhaps
some special header for the specific adaptor. I'd have to
experiment myself to find out.)
The real explanation is that you're jumping too far ahead of
where you are in the learning cycle. Learn the basics first;
there's time enough for Boost later.
.....[SNIP]....
But seriously: I prefixed my suggestion with
"For a more experienced programmer". I did so for a reason.
Don't worry about it yet.
Ok, I understood :) for now, I will just use <algorithm>

I think that's the goal of the exercise:).
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top