#include #include #include #include /************************************************************ * COUNTING ARRAY ENTRIES USING PREDICATES * * Previously, if we wanted to count the entries of an * array satisfying a particular condition, we might * have written a separate function for each condition. * * For example, count_positive() counts the entries * that are strictly greater than zero. * * However, the algorithm for counting entries is * always the same: * * 1. Initialize a counter to zero. * 2. Examine each entry of the array. * 3. If the entry satisfies the condition, * increment the counter. * 4. Return the counter. * * Only the condition changes. * * We can generalize this algorithm by passing the * condition as an argument to the counting function. * * A function that returns a Boolean value is called * a predicate. * * The type * * std::function * * can store any compatible callable object that * accepts a double and returns a value convertible * to bool. * * This includes ordinary functions and lambda * expressions. * * The generalized count() function applies the * supplied predicate to every entry of the array * and counts how often it returns true. ************************************************************/ // Function declarations int main(); std::size_t count_positive( double const array[], std::size_t const capacity ); std::size_t count( double const array[], std::size_t const capacity, std::function const predicate ); bool is_positive( double const x ); bool is_in_0_1( double const x ); bool is_outside_n1_1( double const x ); // Function definitions int main() { std::size_t const data_capacity{ 20 }; double data[data_capacity]{ 6.73, -0.52, -5.52, -8.43, 4.41, 1.19, 5.19, -1.40, 2.55, -9.02, 7.35, 7.34, 9.34, -0.06, 1.12, -2.73, 9.77, 4.71, 2.20, -9.28 }; // Count positive entries using a function // written specifically for that purpose. std::cout << "Greater than zero: " << count_positive( data, data_capacity ) << std::endl; // Count positive entries using the // generalized function and a predicate. std::cout << "Greater than zero: " << count( data, data_capacity, is_positive ) << std::endl; // Count entries in the closed interval [0, 1]. std::cout << "In the interval [0, 1]: " << count( data, data_capacity, is_in_0_1 ) << std::endl; // Count entries outside the closed // interval [-1, 1]. std::cout << "Outside the interval [-1, 1]: " << count( data, data_capacity, is_outside_n1_1 ) << std::endl; // A lambda expression can also be used // as a predicate. // // This lambda returns true if its // argument is strictly less than zero. std::cout << "Less than zero: " << count( data, data_capacity, []( double const x ) { return x < 0.0; } ) << std::endl; // Verify the results. assert( count_positive( data, data_capacity ) == 13 ); assert( count( data, data_capacity, is_positive ) == 13 ); assert( count( data, data_capacity, is_in_0_1 ) == 0 ); assert( count( data, data_capacity, is_outside_n1_1 ) == 18 ); // An empty array contains no entries // satisfying any predicate. assert( count( nullptr, 0, is_positive ) == 0 ); return 0; } /************************************************************ * Count all entries that are strictly positive. * * This function explicitly tests whether each entry * is greater than zero. * * To count entries satisfying another condition, * we would need to write another function. ************************************************************/ std::size_t count_positive( double const array[], std::size_t const capacity ) { assert( array != nullptr || capacity == 0 ); std::size_t positive_count{ 0 }; for ( std::size_t k{ 0 }; k < capacity; ++k ) { if ( array[k] > 0.0 ) { ++positive_count; } } return positive_count; } /************************************************************ * Count the entries satisfying a supplied predicate. * * The predicate accepts a double and returns a * Boolean value. * * For every entry of the array, we call the predicate. * If the predicate returns true, we increment * the counter. * * This function works with any compatible predicate, * so we no longer need a separate counting function * for each condition. ************************************************************/ std::size_t count( double const array[], std::size_t const capacity, std::function const predicate ) { assert( array != nullptr || capacity == 0 ); assert( static_cast( predicate ) ); std::size_t true_count{ 0 }; for ( std::size_t k{ 0 }; k < capacity; ++k ) { if ( predicate( array[k] ) ) { ++true_count; } } return true_count; } /************************************************************ * Return true if x > 0 and false otherwise. * * --|----|----|----o====|====|====|== * -3 -2 -1 0 1 2 3 * * The open circle indicates that zero * is excluded. ************************************************************/ bool is_positive( double const x ) { return x > 0.0; } /************************************************************ * Return true if 0 <= x <= 1 and false otherwise. * * --|----|----|----*====*----|----|-- * -3 -2 -1 0 1 2 3 * * The filled circles indicate that * both endpoints are included. ************************************************************/ bool is_in_0_1( double const x ) { return ( x >= 0.0 ) && ( x <= 1.0 ); } /************************************************************ * Return true if x < -1 or x > 1, * and false otherwise. * * ==|====|====o----|----o====|====|== * -3 -2 -1 0 1 2 3 * * The open circles indicate that * -1 and 1 are excluded. ************************************************************/ bool is_outside_n1_1( double const x ) { return ( x < -1.0 ) || ( x > 1.0 ); }