By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,433 Members | 1,448 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,433 IT Pros & Developers. It's quick & easy.

STL Algorithm Example

P: n/a
I'm teaching myself how to use STL's algorithms, so every time I have a
loop I'm attempting to convert it into an algorithm call...

However, I'm stumpted by this one:

for (vector<double>::iterator raValIt = raVal.begin();
raValIt != raVal.end();
++raValIt)
{
if (*raValIt >= upperBorder)
{
*raValIt -= 360.0;
}
}

Is this just a case where you're better off with a loop? I'm not going
to bother with functor for such a simple function... but it seems too
complex for the standard algorithm options.

Any ideas?

Cheers,
Ross

Nov 3 '05 #1
Share this Question
Share on Google+
16 Replies


P: n/a
On 2005-11-03, zexpe <us****@zexpe.freeserve.co.uk> wrote:
I'm teaching myself how to use STL's algorithms, so every time
I have a loop I'm attempting to convert it into an algorithm
call...

However, I'm stumpted by this one:

for (vector<double>::iterator raValIt = raVal.begin();
raValIt != raVal.end();
++raValIt)
{
if (*raValIt >= upperBorder)
{
*raValIt -= 360.0;
}
}

Is this just a case where you're better off with a loop? I'm
not going to bother with functor for such a simple function...
but it seems too complex for the standard algorithm options.


It's an application of std::transform. But if you don't want to
write a functor then forget it. Sometimes the few especially
simple-minded standard algorithms (transform, for_each) aren't
worth the trouble.

On the other hand, there's boost::lambda which allows you to
build functors on the fly that you can't easily produce with the
standard functors and adaptors.

--
Neil Cerutti
Nov 3 '05 #2

P: n/a
zexpe wrote:
I'm teaching myself how to use STL's algorithms, so every time I have a
loop I'm attempting to convert it into an algorithm call...

However, I'm stumpted by this one:

for (vector<double>::iterator raValIt = raVal.begin();
raValIt != raVal.end();
++raValIt)
{
if (*raValIt >= upperBorder)
{
*raValIt -= 360.0;
}
}

Is this just a case where you're better off with a loop? I'm not going
to bother with functor for such a simple function... but it seems too
complex for the standard algorithm options.


# include <functional>
# include <iostream>

template <class InputIterator, class OutputIterator, class UnaryProc,
class UnaryPredicate>
void transform_if(InputIterator begin, InputIterator end,
OutputIterator out, UnaryProc op, UnaryPredicate pred)
{
while (begin != end)
{
if (pred(*begin))
*out = op(*begin);

++begin;
++out;
}
}

void f(std::vector<double> &v, double upperBorder)
{
transform_if(
v.begin(), v.end(), v.begin(),
std::bind2nd(std::minus<double>(), 360.0),
std::bind2nd(std::greater_equal<double>(), upperBorder));
}
Jonathan

Nov 3 '05 #3

P: n/a
Jonathan Mcdougall wrote:
void f(std::vector<double> &v, double upperBorder)
{
transform_if(
v.begin(), v.end(), v.begin(),
std::bind2nd(std::minus<double>(), 360.0),
std::bind2nd(std::greater_equal<double>(), upperBorder));
}


What's transform_if ? And do you think this is more readable to an
average C++ programmer (who may have to work with your code later) than
the explicit loop?

I am all in favour of STL algorithms, but unfortunately there are many
cases where STL algorithms are not very usefull unless we introduce
closures.

--

Valentin Samko - http://www.valentinsamko.com

Nov 3 '05 #4

P: n/a
Very nice solution if transform_if was part of the standard... but it
isn't and I generally I prefer not to create my own algorithms - future
readers might be confused by transform_if() as it's not standard (I
wish it was!). Though I do prefer an algorithm solution over writing my
own functor for such a simple problem. Thanks for suggesting something
I hadn't thought of...

Ross

Nov 3 '05 #5

P: n/a
Valentin.Samko wrote:
Jonathan Mcdougall wrote:
void f(std::vector<double> &v, double upperBorder)
{
transform_if(
v.begin(), v.end(), v.begin(),
std::bind2nd(std::minus<double>(), 360.0),
std::bind2nd(std::greater_equal<double>(), upperBorder));
}
What's transform_if ?


Umm.. it was defined just before f(), you know, in the part you
snipped.

template <class InputIterator, class OutputIterator, class UnaryProc,
class UnaryPredicate>
void transform_if( InputIterator begin, InputIterator end,
OutputIterator out, UnaryProc op, UnaryPredicate pred)
{
while (begin != end)
{
if (pred(*begin))
*out = op(*begin);

++begin;
++out;
}
}
And do you think this is more readable to an
average C++ programmer (who may have to work with your code later) than
the explicit loop?


Personally, I think it is awful, but that's my opinion. Just to remind
you, the OP asked a question and I answered as best as I could.

Tell me, was I wrong?
Jonathan

Nov 3 '05 #6

P: n/a
Thanks. I hadn't heard of boost::lambda. Nice idea... I may well learn
it. I don't like the hefty iterator filled-loops for STL containers,
and using the old C-style indices just seems wrong, so boost::lambda
may well be the way forward!

Although I'm not a big fan of creating your own algorithms, I don't
mind adding in a new official library if it's useful. It's more to
obvious future developers.

Ross

Nov 3 '05 #7

P: n/a
Oops. Sorry for the lack of quotations. First time on Google Groups
rather than the old newsgroup readers... and it doesn't make it easy
for you to put a quotation in your reply!

Ross

Nov 3 '05 #8

P: n/a
zexpe wrote:
Oops. Sorry for the lack of quotations. First time on Google Groups
rather than the old newsgroup readers... and it doesn't make it easy
for you to put a quotation in your reply!


Select Show Options near the poster's name and click "Reply".
Jonathan

Nov 3 '05 #9

P: n/a
Jonathan Mcdougall wrote:
Select Show Options near the poster's name and click "Reply".


Ah, that's better! Thanks!

Ross

Nov 3 '05 #10

P: n/a
Jonathan Mcdougall wrote:
What's transform_if ?

Umm.. it was defined just before f(), you know, in the part you
snipped.

I missed it. Btw, you have a bug there where you increment 'out' even when you should not.
And do you think this is more readable to an
average C++ programmer (who may have to work with your code later) than
the explicit loop?


Personally, I think it is awful, but that's my opinion. Just to remind
you, the OP asked a question and I answered as best as I could.
Tell me, was I wrong?

I just agreed with the original poster that this example is too complex for the standard
algorithms, and he'd be better off with a loop. I also understand that he asked how to do
this with standard binders without leaving the scope to write a predicate (or a new
algorithm). There is nothing wrong about your answer, I just made a comment regarding the
readability of the standard binders (tr1::bind gets it better, but it is still quite
primitive).

I guess the only generic way to solve the problems where the standard algorithms are too
complex is to introduce closures in C++. This also make debugging them much more simple (I
wouldn't like to debug a complex closure built with tr1::bind).

--

Valentin Samko - http://www.valentinsamko.com
Nov 3 '05 #11

P: n/a
Valentin Samko wrote:
Jonathan Mcdougall wrote:
What's transform_if ?

Umm.. it was defined just before f(), you know, in the part you
snipped.

I missed it. Btw, you have a bug there where you increment 'out' even when you should
not.


Do you mean I should not increment it when the predicate is false?
Well, since that function is not standard, I suppose I should define
its behavior.

For each element in the source range, writes
.op(elem) if the predicate is true
.elem is the predicate is false
to the destination range starting with out.
And do you think this is more readable to an
average C++ programmer (who may have to work with your code later) than
the explicit loop?


Personally, I think it is awful, but that's my opinion. Just to remind
you, the OP asked a question and I answered as best as I could.
Tell me, was I wrong?


I just agreed with the original poster that this example is too complex for the standard
algorithms, and he'd be better off with a loop. I also understand that he asked how to do
this with standard binders without leaving the scope to write a predicate (or a new
algorithm). There is nothing wrong about your answer, I just made a comment regarding
the readability of the standard binders (tr1::bind gets it better, but it is still quite
primitive).

I guess the only generic way to solve the problems where the standard algorithms are
too complex is to introduce closures in C++. This also make debugging them much
more simple (I wouldn't like to debug a complex closure built with tr1::bind).


We agree.
Jonathan

Nov 3 '05 #12

P: n/a
zexpe wrote:
Very nice solution if transform_if was part of the standard... but it
isn't and I generally I prefer not to create my own algorithms - future
readers might be confused by transform_if() as it's not standard (I
wish it was!). Though I do prefer an algorithm solution over writing my
own functor for such a simple problem. Thanks for suggesting something
I hadn't thought of...

Ross


Put it in a namespace. Example below. Since you're calling
my_algorithms::transform_if(), there should be no confusion with the
standard library.
# include <functional>
# include <iostream>

namespace my_algorithms {
template <class InputIterator, class OutputIterator, class UnaryProc,
class UnaryPredicate>
void transform_if(InputIterator begin, InputIterator end,
OutputIterator out, UnaryProc op, UnaryPredicate pred)
{
while (begin != end)
{
if (pred(*begin))
*out = op(*begin);

++begin;
++out;
}
}
}

void f(std::vector<double> &v, double upperBorder)
{
my_algorithms::transform_if(
v.begin(), v.end(), v.begin(),
std::bind2nd(std::minus<double>(), 360.0),
std::bind2nd(std::greater_equal<double>(), upperBorder));
}
Nov 3 '05 #13

P: n/a
Jonathan Mcdougall schrieb:
Valentin Samko wrote:
I missed it. Btw, you have a bug there where you increment 'out' even when you should
not.
Do you mean I should not increment it when the predicate is false?
Well, since that function is not standard, I suppose I should define
its behavior.

For each element in the source range, writes
.op(elem) if the predicate is true
.elem is the predicate is false
to the destination range starting with out.


It doesn't write the element to out when predicate is false. You missed
the else part. So it won't work if source range and destination range
are not the same.

[...] while (begin != end)
{
if (pred(*begin))
*out = op(*begin);

++begin;
++out;
}

[...]

Thomas
Nov 3 '05 #14

P: n/a
Thomas J. Gritzan wrote:
Jonathan Mcdougall schrieb:
Valentin Samko wrote:
I missed it. Btw, you have a bug there where you increment 'out' even when you should
not.


Do you mean I should not increment it when the predicate is false?
Well, since that function is not standard, I suppose I should define
its behavior.

For each element in the source range, writes
.op(elem) if the predicate is true
.elem is the predicate is false
to the destination range starting with out.


It doesn't write the element to out when predicate is false. You missed
the else part. So it won't work if source range and destination range
are not the same.


template <class In, class Out, class Proc, class Pred>
Out transform_if(In begin, In end, Out out, Proc op, Pred pred)
{
while (begin != end)
{
if (pred(*begin))
*out = op(*begin);
else
*out = *begin;

++begin;
++out;
}

return out;
}

This should work all right.
Jonathan

Nov 4 '05 #15

P: n/a
Jonathan Mcdougall wrote:
template <class In, class Out, class Proc, class Pred>
Out transform_if(In begin, In end, Out out, Proc op, Pred pred)
{
while (begin != end)
{
if (pred(*begin))
*out = op(*begin);
else
*out = *begin;

++begin;
++out;
}

return out;
}


I have an efficiency question. The original for-loop used -= and is
clearly a very efficient operation. Although the vector in my
application is small. This loop will be performed many times on
different vectors, totalling in a very large number of operations. If I
redesigned transform_if() in the following way, which is inconsistent
with std::transform(), I'd imagine the compiler would be able to
replace *begin = op(*begin); with the equivalent -= operation:

template <class In, class Proc, class Pred>
void transform_if(In begin, In end, Proc op, Pred pred)
{
while (begin != end)
{
if (pred(*begin))
*begin = op(*begin);

++begin;
}
}

So, my question is... is this solution as efficient as the for-loop,
with the only draw back being it's not adhering to the usual design of
std::transform()?

Ross

Nov 4 '05 #16

P: n/a
red floyd wrote:
Put it in a namespace. Example below. Since you're calling
my_algorithms::transform_if(), there should be no confusion with the
standard library.


Thanks for the suggestion. That's a good application of namespaces
(which IMHO often just bloat code, making it harder to follow). I'm
beginning to warm to the user-defined algorithm solution.

Ross

Nov 4 '05 #17

This discussion thread is closed

Replies have been disabled for this discussion.