454,433 Members | 1,448 Online
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::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
16 Replies

 P: n/a On 2005-11-03, 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::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::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 # include template 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 &v, double upperBorder) { transform_if( v.begin(), v.end(), v.begin(), std::bind2nd(std::minus(), 360.0), std::bind2nd(std::greater_equal(), upperBorder)); } Jonathan Nov 3 '05 #3

 P: n/a Jonathan Mcdougall wrote: void f(std::vector &v, double upperBorder) { transform_if( v.begin(), v.end(), v.begin(), std::bind2nd(std::minus(), 360.0), std::bind2nd(std::greater_equal(), 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 &v, double upperBorder) { transform_if( v.begin(), v.end(), v.begin(), std::bind2nd(std::minus(), 360.0), std::bind2nd(std::greater_equal(), upperBorder)); } What's transform_if ? Umm.. it was defined just before f(), you know, in the part you snipped. template 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 # include namespace my_algorithms { template 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 &v, double upperBorder) { my_algorithms::transform_if( v.begin(), v.end(), v.begin(), std::bind2nd(std::minus(), 360.0), std::bind2nd(std::greater_equal(), 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 shouldnot. 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 shouldnot. 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 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 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 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.