
The documentation for boost range states that count_if can be expressed as count using a filtered adaptor and then goes on to say that no algorithm needs the _if suffix. I'm having trouble seeing how that is the case. Here is the relevant section from the latest (1.49 beta) documentation http://www.boost.org/doc/libs/1_49_0_beta1/libs/range/doc/html/range/referen.... Range Adaptor alternative to count_if algorithm http://www.boost.org/doc/libs/1_49_0_beta1/libs/range/doc/html/range/referen... boost::count_if( rng, pred ); can be expressed as boost::count( rng | boost::adaptors::filtered(pred), out ); What this means is that /*no*/ algorithm with the |_if| suffix is needed. First of all, what is "out"? I think this is supposed to be "value" as count requires the value to compare against for the count. But, since it does require the value, this makes the function fundamentally different than count_if which will only count the values that match the predicate. As far as I can tell, this means that "count" will filter values both by the predicate and by the value. What am I missing? How can count_if be properly expressed as count. To me it seems like it can't. -- Bill

On 2/9/2012 3:08 PM, Bill Buklis wrote:
What am I missing? How can count_if be properly expressed as count. To me it seems like it can't.
The value to compare against would be part of the 'pred', either hard-coded into it, or bound as an argument to a function that takes two arguments.

On 2/9/2012 11:26 PM, John M. Dlugosz wrote:
On 2/9/2012 3:08 PM, Bill Buklis wrote:
What am I missing? How can count_if be properly expressed as count. To me it seems like it can't.
The value to compare against would be part of the 'pred', either hard-coded into it, or bound as an argument to a function that takes two arguments.
That makes sense, but how would that work? For example, let's say I wanted to count the number of non-zero values in an array. With count_if I can easily do this: namespace bll = boost::lambda; int data[] = { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0 }; size_t k = boost::count_if(data, bll::_1 != 0); The documentation implies that this is possible with boost::count using a filtered adaptor. Is it? This line isn't valid: size_t n = boost::count(data | boost::adaptors::filtered(bll::_1 != bll::_2), 0); and this line will return 0 matches: size_t n = boost::count(data | boost::adaptors::filtered(bll::_1 != 0), 0); I'm sure I must be missing the obvious somewhere. Thanks in advance for enlightening me. -- Bill

From: boostusr@pbjzone.com
On 2/9/2012 11:26 PM, John M. Dlugosz wrote:
On 2/9/2012 3:08 PM, Bill Buklis wrote:
What am I missing? How can count_if be properly expressed as count. To me it seems like it can't.
The value to compare against would be part of the 'pred', either hard-coded into it, or bound as an argument to a function that takes two arguments.
That makes sense, but how would that work? For example, let's say I wanted to count the number of non-zero values in an array. With count_if I can easily do this:
namespace bll = boost::lambda; int data[] = { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0 }; size_t k = boost::count_if(data, bll::_1 != 0);
The documentation implies that this is possible with boost::count using a filtered adaptor. Is it?
This line isn't valid: size_t n = boost::count(data | boost::adaptors::filtered(bll::_1 != bll::_2), 0);
and this line will return 0 matches: size_t n = boost::count(data | boost::adaptors::filtered(bll::_1 != 0), 0);
I'm sure I must be missing the obvious somewhere. Thanks in advance for enlightening me.
I don't think you're missing anything, I think the example is wrong. A working alternative to: boost::count_if(data, bll::_1 != 0) would be: boost::distance(data | filtered(bll::_1 != 0)) since boost::distance counts the total number of elements in the range. Regards, Nate

On 2/10/2012 11:39 AM, Bill Buklis wrote:
What am I missing? How can count_if be properly expressed as count. To me it seems like it can't.
I agree. "count returns the number of elements x in rng where x == val is true." If you filter the original range using the predicate instead, you don't want to then compare them all against some constant. If you did so, you would need a special value such that every one of them compared true. You just want to count the number of items in the range you get after filtering. The obvious boost::size requires a bidirectional range, and is probably less efficient then we would want. Nathan mentioned boost::distance, which is hard to find in the documentation. But I see it listed on the synopsis under Forward Range functions. I guess it's missing from the page doc/range/concepts/forward_range.html In general, it is true that having two algorithms "do something with or to each element" and "same, but selecting elements via a predicate" can be generalized to using the first (only) with a range filter. But count and count_if are not such a pair. count also has a built-in predicate, but of the form el==value, rather than acting implicitly on all the elements. —John

On 2/12/2012 7:03 AM, John M. Dlugosz wrote:
On 2/10/2012 11:39 AM, Bill Buklis wrote:
What am I missing? How can count_if be properly expressed as count. To me it seems like it can't.
I agree. "count returns the number of elements x in rng where x == val is true." If you filter the original range using the predicate instead, you don't want to then compare them all against some constant. If you did so, you would need a special value such that every one of them compared true.
You just want to count the number of items in the range you get after filtering. The obvious boost::size requires a bidirectional range, and is probably less efficient then we would want.
Nathan mentioned boost::distance, which is hard to find in the documentation. But I see it listed on the synopsis under Forward Range functions. I guess it's missing from the page doc/range/concepts/forward_range.html
In general, it is true that having two algorithms "do something with or to each element" and "same, but selecting elements via a predicate" can be generalized to using the first (only) with a range filter.
But count and count_if are not such a pair. count also has a built-in predicate, but of the form el==value, rather than acting implicitly on all the elements.
—John
Indeed, the documentation must be wrong. Hopefully it can be appropriately fixed soon. That is an excellent suggestion about using distance. I had not thought of that, nor, come to think of it, did I even know that there was a boost::distance function. But, it makes sense. On the other hand, I do have to wonder if using "distance" for "count" would obfuscate the code. In general, I think I would rather use count_if just for clarity. But, at least the statement that the "_if functions aren't required", still holds true even if it may not be rather obvious which one to use. -- Bill

Out of curiosity I have one more variation on _if vs non _if. Since you can use distance instead of count_if, how would you go about replacing find_if with a non _if variant? For example: struct data { int a; int b; }; // function object that takes two data parameters - contents unimportant for the example struct match_data; std::vector<data> data_range; data search_value; boost::find_if( data_range, boost::bind(match_data(), _1, search_value) ); Thanks, -- Bill

Hi Bill,
On Tue, Feb 14, 2012 at 11:26 AM, Bill Buklis
struct data { int a; int b; };
// function object that takes two data parameters - contents unimportant for the example struct match_data;
std::vector<data> data_range; data search_value;
boost::find_if( data_range, boost::bind(match_data(), _1, search_value) );
Interesting question. How about:
boost::begin(data_range | filtered(boost::bind(match_data(), _1,
search_value))); ?
HTH,
Nate
P.S. Had to compile it to prove it to myself: (cygwin g++ 4.5.3, old
boost trunk)
$ cat simple.cpp
#include

On Tue, Feb 14, 2012 at 11:26 AM, Bill Buklis
wrote: struct data { int a; int b; };
// function object that takes two data parameters - contents unimportant for the example struct match_data;
std::vector<data> data_range; data search_value;
boost::find_if( data_range, boost::bind(match_data(), _1, search_value) );
Interesting question. How about:
boost::begin(data_range | filtered(boost::bind(match_data(), _1, search_value))); ?
Yup, and then you can call base() on the resulting filter_iterator to recover the iterator into the original range (if you need that). The broader point, I think, is that the statement in the documentation for range adaptors that they obsolete the "_if" variants of algorithms, is misleading at best. The "_if" variant reduces to the plain version + filtered adaptor only in cases where the "_if" variant adds an additional constraint over the plain version (as in e.g. copy_if). For algorihms where the "_if" variant is a generalization of the plain version (i.e. the constraint "the range element is equal to the given value" is generalized to "the range element satisfies this predicate" (e.g. count_if, find_if), the "_if" variant does *not* reduce to the plain version + filtered adaptor. We happened to be able to reduce count_if and find_if to *other* range algorithms + filtered adaptor, because we found other range algorithms that do what we want (namely, distance() and begin()), but in general such a different range algorithm (that combines with the filtered adaptor to do what the "_if" version of the original algorithm did) may not exist. Regards, Nate

Den 14-02-2012 21:16, Nathan Ridge skrev:
The broader point, I think, is that the statement in the documentation for range adaptors that they obsolete the "_if" variants of algorithms, is misleading at best.
Thanks to all for the discussion and issues raised. We'll moderate the discussion somewhat, and provide better examples. If there are more examples of stuff that is hard to do, please keep posting them. kind regards -Thorsten
participants (5)
-
Bill Buklis
-
John M. Dlugosz
-
Nathan Crookston
-
Nathan Ridge
-
Thorsten Ottosen