This is a follow-up question for A recursive_count Function For Various Type Arbitrary Nested Iterable Implementation in C++. Thanks to G. Sliepen's answer. Based on the mentioned suggestion, the naming of the function for getting the element count in arbitrary nested iterables is updated into recursive_size
. Here, I am trying to implement the functions (recursive_count
and recursive_count_if
) which purpose are similar to std::count
and std::count_if
and can be used in various type arbitrary nested iterable things. In the template function recursive_count
, the first parameter is an input nested iterable object and the second parameter is the target value to search for.
// recursive_count implementation
template<class T1, class T2> requires (!is_elements_iterable<T1> && is_iterable<T1>)
auto recursive_count(const T1& input, const T2 target)
{
return std::count(input.begin(), input.end(), target);
}
// for loop version
template<class T1, class T2> requires (is_elements_iterable<T1>)
auto recursive_count(const T1& input, const T2 target)
{
size_t output{};
for (auto &element : input)
{
output += recursive_count(element, target);
}
return output;
}
In the template function recursive_count_if
, the first parameter is also an input nested iterable object and the second parameter is a unary predicate which returns true
for the required elements.
// recursive_count_if implementation
template<class T1, class T2> requires (!is_elements_iterable<T1> && is_iterable<T1>)
auto recursive_count_if(const T1& input, const T2 predicate)
{
return std::count_if(input.begin(), input.end(), predicate);
}
// for loop version
template<class T1, class T2> requires (is_elements_iterable<T1>)
auto recursive_count_if(const T1& input, const T2 predicate)
{
size_t output{};
for (auto &element : input)
{
output += recursive_count_if(element, predicate);
}
return output;
}
Some test cases for recursive_count
template function:
// std::vector<std::vector<int>> case
std::vector<int> test_vector{ 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };
std::vector<decltype(test_vector)> test_vector2;
test_vector2.push_back(test_vector);
test_vector2.push_back(test_vector);
test_vector2.push_back(test_vector);
// determine how many integers in a std::vector<std::vector<int>> match a target value.
int target1 = 3;
int target2 = 5;
int num_items1 = recursive_count(test_vector2, target1);
int num_items2 = recursive_count(test_vector2, target2);
std::cout << "number: " << target1 << " count: " << num_items1 << '\n';
std::cout << "number: " << target2 << " count: " << num_items2 << '\n';
// std::deque<std::deque<int>> case
std::deque<int> test_deque;
test_deque.push_back(1);
test_deque.push_back(2);
test_deque.push_back(3);
std::deque<decltype(test_deque)> test_deque2;
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
// determine how many integers in a std::deque<std::deque<int>> match a target value.
int num_items3 = recursive_count(test_deque2, target1);
int num_items4 = recursive_count(test_deque2, target2);
std::cout << "number: " << target1 << " count: " << num_items3 << '\n';
std::cout << "number: " << target2 << " count: " << num_items4 << '\n';
Some test cases for recursive_count_if
template function:
// std::vector<std::vector<int>> case
std::vector<int> test_vector{ 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };
std::vector<decltype(test_vector)> test_vector2;
test_vector2.push_back(test_vector);
test_vector2.push_back(test_vector);
test_vector2.push_back(test_vector);
// use a lambda expression to count elements divisible by 3.
int num_items1 = recursive_count_if(test_vector2, [](int i) {return i % 3 == 0; });
std::cout << "#number divisible by three: " << num_items1 << '\n';
// std::deque<std::deque<int>> case
std::deque<int> test_deque;
test_deque.push_back(1);
test_deque.push_back(2);
test_deque.push_back(3);
std::deque<decltype(test_deque)> test_deque2;
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
// use a lambda expression to count elements divisible by 3.
int num_items2 = recursive_count_if(test_deque2, [](int i) {return i % 3 == 0; });
std::cout << "#number divisible by three: " << num_items2 << '\n';
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A recursive_count Function For Various Type Arbitrary Nested Iterable Implementation in C++
What changes has been made in the code since last question?
The function for getting the element count in arbitrary nested iterables is renamed into
recursive_size
.Besides the total element count, I am trying to implement the functions (
recursive_count
andrecursive_count_if
) which purpose are similar tostd::count
andstd::count_if
and can be used in various type arbitrary nested iterable things here.
Why a new review is being asked for?
As similar as G. Sliepen's answer mentioned, there is another version of the last overload
recursive_count
template function implementation withstd::transform_reduce
:// transform_reduce version template<class T1, class T2> requires (is_elements_iterable<T1>) auto recursive_count(const T1& input, const T2 target) { return std::transform_reduce(std::begin(input), std::end(input), std::size_t{}, std::plus<std::size_t>(), [target](auto& element) { return recursive_count(element, target); }); }
Also, there is another version of the last overload
recursive_count_if
template function implementation withstd::transform_reduce
:// transform_reduce version template<class T1, class T2> requires (is_elements_iterable<T1>) auto recursive_count_if(const T1& input, const T2 predicate) { return std::transform_reduce(std::begin(input), std::end(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto& element) { return recursive_count_if(element, predicate); }); }
I am wondering which version is more readable.
A Godbolt link for this (using
std::transform_reduce
) version is here.If there is any possible improvement, please let me know.
concept is_iterable
does, for example. \$\endgroup\$