Это дополнительный вопрос для функции recursive_count_if для произвольной вложенной итерируемой реализации произвольного типа в C ++ и функции recursive_count_if с уровнем распаковки для реализации произвольной вложенной итерируемой произвольной формы в C ++. Функция recursive_count_if
реализуется с помощью а std::ranges::range
Вход и предикат. Я пытаюсь реализовать функцию batch_recursive_count_if
для обработки вариантов использования нескольких предикатов (как в примере ниже).
auto predicator1 = [](auto& i) {return i == 1; };
auto predicator2 = [](auto& i) {return i == 2; };
auto predicator3 = [](auto& i) {return i == 3; };
auto predicator4 = [](auto& i) {return i == 4; };
auto predicator5 = [](auto& i) {return i == 5; };
auto predicator6 = [](auto& i) {return i == 6; };
auto predicator7 = [](auto& i) {return i == 7; };
auto predicator8 = [](auto& i) {return i == 8; };
auto predicator9 = [](auto& i) {return i == 9; };
auto predicator10 = [](auto& i) {return i == 10; };
Форма API похожа на std::vector<int> counts = batch_recursive_count_if<unwrap_level>(ranges, predicate1, predicate2, predicate3, ...);
который включает расширенные параметры предиката, а возвращаемый тип — std::vector
(для представления последовательности вывода, которая является результатом каждого предиката).
Экспериментальная реализация
// recursive_count_if implementation (the version with unwrap_level)
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred>
auto recursive_count_if(const T& input, const Pred& predicate)
{
if constexpr (unwrap_level > 1)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if<unwrap_level - 1>(element, predicate);
});
}
else
{
return std::count_if(std::ranges::cbegin(input), std::ranges::cend(input), predicate);
}
}
// batch_recursive_count_if implementation (the version with unwrap_level)
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1)
{
std::vector<decltype(recursive_count_if<unwrap_level>(input, predicate1))> output;
output.push_back(recursive_count_if<unwrap_level>(input, predicate1));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1);
output.push_back(recursive_count_if<unwrap_level>(input, predicate2));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2);
output.push_back(recursive_count_if<unwrap_level>(input, predicate3));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3);
output.push_back(recursive_count_if<unwrap_level>(input, predicate4));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4);
output.push_back(recursive_count_if<unwrap_level>(input, predicate5));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5);
output.push_back(recursive_count_if<unwrap_level>(input, predicate6));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6);
output.push_back(recursive_count_if<unwrap_level>(input, predicate7));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7, class Pred8>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7, const Pred8& predicate8)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6, predicate7);
output.push_back(recursive_count_if<unwrap_level>(input, predicate8));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7, class Pred8, class Pred9>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7, const Pred8& predicate8, const Pred9& predicate9)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6, predicate7, predicate8);
output.push_back(recursive_count_if<unwrap_level>(input, predicate9));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7, class Pred8, class Pred9, class Pred10>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7, const Pred8& predicate8, const Pred9& predicate9, const Pred10& predicate10)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6, predicate7, predicate8, predicate9);
output.push_back(recursive_count_if<unwrap_level>(input, predicate10));
return output;
}
Тестовые кейсы
Приведенные ниже тестовые примеры включают:
Подсчет
int
элемент вstd::vector<std::vector<int>>
что равно указанному номеру.Подсчет
int
элемент вstd::deque<std::deque<int>>
что равно указанному номеру.Подсчет
std::string
элемент вstd::vector<std::vector<std::string>>
что равно указанной строке.Подсчет
std::vector<std::vector<int>>
элемент вstd::vector<std::vector<std::vector<int>>>
что соответствует указанному шаблону.
// std::vector<std::vector<int>> case
std::cout << "std::vector<std::vector<int>> case:" << 'n';
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 lambda expressions to count the elements which is equal to 1 to 10.
auto predicator1 = [](auto& i) {return i == 1; };
std::cout << "#number is 1: " << recursive_count_if<2>(test_vector2, predicator1) << 'n';
auto predicator2 = [](auto& i) {return i == 2; };
auto predicator3 = [](auto& i) {return i == 3; };
auto predicator4 = [](auto& i) {return i == 4; };
auto predicator5 = [](auto& i) {return i == 5; };
auto predicator6 = [](auto& i) {return i == 6; };
auto predicator7 = [](auto& i) {return i == 7; };
auto predicator8 = [](auto& i) {return i == 8; };
auto predicator9 = [](auto& i) {return i == 9; };
auto predicator10 = [](auto& i) {return i == 10; };
auto batch_output1 = batch_recursive_count_if<2>(test_vector2, predicator1, predicator2, predicator3, predicator4, predicator5, predicator6, predicator7, predicator8, predicator9, predicator10);
std::cout << "Each element in batch_output1: " << 'n';
for (auto& element : batch_output1)
{
std::cout << element << 'n';
}
std::cout << 'n';
// std::deque<std::deque<int>> case
std::cout << "std::deque<std::deque<int>> case:" << 'n';
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 lambda expressions to count the elements which is equal to 1 to 10.
std::cout << "#number is 1: " << recursive_count_if<2>(test_deque2, predicator1) << 'n';
auto batch_output2 = batch_recursive_count_if<2>(test_deque2, predicator1, predicator2, predicator3, predicator4, predicator5, predicator6, predicator7, predicator8, predicator9, predicator10);
std::cout << "Each element in batch_output1: " << 'n';
for (auto& element : batch_output2)
{
std::cout << element << 'n';
}
std::cout << 'n';
// std::vector<std::vector<std::string>> case
std::cout << "std::vector<std::vector<std::string>>:" << 'n';
std::vector<std::vector<std::string>> v = { {"hello"}, {"world"} };
auto is_hello = [](auto& i) { return i == "hello"; };
auto is_world = [](auto& i) { return i == "world"; };
std::cout << "recursive_count_if output of is_hello:" << recursive_count_if<2>(v, is_hello) << std::endl;
auto batch_output3 = batch_recursive_count_if<2>(v, is_hello, is_world);
std::cout << "Each element in batch_output1: " << 'n';
for (auto& element : batch_output3)
{
std::cout << element << 'n';
}
std::cout << 'n';
// Count specific std::vector<std::vector<int>> element in std::vector<std::vector<std::vector<int>>> case
std::cout << "Count specific std::vector<std::vector<int>> element in std::vector<std::vector<std::vector<int>>> case:" << std::endl;
std::vector<decltype(test_vector2)> test_vector3;
for (size_t i = 0; i < 3; i++)
{
test_vector3.push_back(test_vector2);
}
auto batch_output4 = batch_recursive_count_if<1>(test_vector3,
[test_vector2](auto& element)
{
if (element.size() != test_vector2.size())
{
return false;
}
return std::equal(element.begin(), element.end(), test_vector2.begin());
},
[test_vector2](auto& element)
{
auto vector_for_comparison = test_vector2;
vector_for_comparison.push_back(std::vector<int>{12, 2, 3});
if (element.size() != vector_for_comparison.size())
{
return false;
}
return std::equal(vector_for_comparison.begin(), vector_for_comparison.end(), vector_for_comparison.begin());
});
for (auto& element : batch_output4)
{
std::cout << element << 'n';
}
std::cout << 'n';
Результат тестового кода выше:
std::vector<std::vector<int>> case:
#number is 1: 3
Each element in batch_output1:
3
3
6
6
0
0
3
3
3
3
std::deque<std::deque<int>> case:
#number is 1: 3
Each element in batch_output1:
3
3
3
0
0
0
0
0
0
0
std::vector<std::vector<std::string>>:
recursive_count_if output of is_hello:1
Each element in batch_output1:
1
1
Count specific std::vector<std::vector<int>> element in std::vector<std::vector<std::vector<int>>> case:
3
0
Полный код тестирования
Полный код тестирования:
// A batch_recursive_count_if Function with Unwrap Level for Various Type Arbitrary Nested Iterable Implementation in C++
#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <complex>
#include <concepts>
#include <deque>
#include <execution>
#include <exception>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <mutex>
#include <numeric>
#include <optional>
#include <ranges>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
//#define USE_BOOST_MULTIDIMENSIONAL_ARRAY
#ifdef USE_BOOST_MULTIDIMENSIONAL_ARRAY
#include <boost/multi_array.hpp>
#include <boost/multi_array/algorithm.hpp>
#include <boost/multi_array/base.hpp>
#include <boost/multi_array/collection_concept.hpp>
#endif
template<typename T>
concept is_back_inserterable = requires(T x)
{
std::back_inserter(x);
};
template<typename T>
concept is_inserterable = requires(T x)
{
std::inserter(x, std::ranges::end(x));
};
template<typename T>
concept is_minusable = requires(T x) { x - x; };
template<typename T1, typename T2>
concept is_minusable2 = requires(T1 x1, T2 x2) { x1 - x2; };
#ifdef USE_BOOST_MULTIDIMENSIONAL_ARRAY
template<typename T>
concept is_multi_array = requires(T x)
{
x.num_dimensions();
x.shape();
boost::multi_array(x);
};
#endif
template<typename T1, typename T2>
concept is_std_powable = requires(T1 x1, T2 x2)
{
std::pow(x1, x2);
};
// recursive_count implementation
template<std::ranges::input_range Range, typename T>
constexpr auto recursive_count(const Range& input, const T& target)
{
return std::count(std::ranges::cbegin(input), std::ranges::cend(input), target);
}
// transform_reduce version
template<std::ranges::input_range Range, typename T>
requires std::ranges::input_range<std::ranges::range_value_t<Range>>
constexpr auto recursive_count(const Range& input, const T& target)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [target](auto&& element) {
return recursive_count(element, target);
});
}
// recursive_count implementation (with execution policy)
template<class ExPo, std::ranges::input_range Range, typename T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr auto recursive_count(ExPo execution_policy, const Range& input, const T& target)
{
return std::count(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), target);
}
template<class ExPo, std::ranges::input_range Range, typename T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) && (std::ranges::input_range<std::ranges::range_value_t<Range>>)
constexpr auto recursive_count(ExPo execution_policy, const Range& input, const T& target)
{
return std::transform_reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [execution_policy, target](auto&& element) {
return recursive_count(execution_policy, element, target);
});
}
// recursive_count_if implementation
template<class T, std::invocable<T> Pred>
constexpr std::size_t recursive_count_if(const T& input, const Pred& predicate)
{
return predicate(input) ? 1 : 0;
}
template<std::ranges::input_range Range, class Pred>
requires (!std::invocable<Pred, Range>)
constexpr auto recursive_count_if(const Range& input, const Pred& predicate)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if(element, predicate);
});
}
// recursive_count_if implementation (with execution policy)
template<class ExPo, class T, std::invocable<T> Pred>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr std::size_t recursive_count_if(ExPo execution_policy, const T& input, const Pred& predicate)
{
return predicate(input) ? 1 : 0;
}
template<class ExPo, std::ranges::input_range Range, class Pred>
requires ((std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) && (!std::invocable<Pred, Range>))
constexpr auto recursive_count_if(ExPo execution_policy, const Range& input, const Pred& predicate)
{
return std::transform_reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if(element, predicate);
});
}
// recursive_count_if implementation (the version with unwrap_level)
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred>
auto recursive_count_if(const T& input, const Pred& predicate)
{
if constexpr (unwrap_level > 1)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if<unwrap_level - 1>(element, predicate);
});
}
else
{
return std::count_if(std::ranges::cbegin(input), std::ranges::cend(input), predicate);
}
}
// batch_recursive_count_if implementation (the version with unwrap_level)
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1)
{
std::vector<decltype(recursive_count_if<unwrap_level>(input, predicate1))> output;
output.push_back(recursive_count_if<unwrap_level>(input, predicate1));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1);
output.push_back(recursive_count_if<unwrap_level>(input, predicate2));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2);
output.push_back(recursive_count_if<unwrap_level>(input, predicate3));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3);
output.push_back(recursive_count_if<unwrap_level>(input, predicate4));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4);
output.push_back(recursive_count_if<unwrap_level>(input, predicate5));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5);
output.push_back(recursive_count_if<unwrap_level>(input, predicate6));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6);
output.push_back(recursive_count_if<unwrap_level>(input, predicate7));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7, class Pred8>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7, const Pred8& predicate8)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6, predicate7);
output.push_back(recursive_count_if<unwrap_level>(input, predicate8));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7, class Pred8, class Pred9>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7, const Pred8& predicate8, const Pred9& predicate9)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6, predicate7, predicate8);
output.push_back(recursive_count_if<unwrap_level>(input, predicate9));
return output;
}
template<std::size_t unwrap_level = 1, std::ranges::range T, class Pred1, class Pred2, class Pred3, class Pred4, class Pred5, class Pred6, class Pred7, class Pred8, class Pred9, class Pred10>
auto batch_recursive_count_if(const T& input, const Pred1& predicate1, const Pred2& predicate2, const Pred3& predicate3, const Pred4& predicate4, const Pred5& predicate5, const Pred6& predicate6, const Pred7& predicate7, const Pred8& predicate8, const Pred9& predicate9, const Pred10& predicate10)
{
auto output = batch_recursive_count_if<unwrap_level>(input, predicate1, predicate2, predicate3, predicate4, predicate5, predicate6, predicate7, predicate8, predicate9);
output.push_back(recursive_count_if<unwrap_level>(input, predicate10));
return output;
}
// recursive_max implementation
template<std::totally_ordered T>
constexpr auto recursive_max(T number)
{
return number;
}
template<std::ranges::range T>
constexpr auto recursive_max(const T& numbers)
{
auto maxValue = recursive_max(numbers.at(0));
for (auto& element : numbers)
{
maxValue = std::max(maxValue, recursive_max(element));
}
return maxValue;
}
// recursive_print implementation
template<std::ranges::input_range Range>
constexpr auto recursive_print(const Range& input, const int level = 0)
{
auto output = input;
std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
std::ranges::transform(std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output),
[level](auto&& x)
{
std::cout << std::string(level, ' ') << x << std::endl;
return x;
}
);
return output;
}
template<std::ranges::input_range Range> requires (std::ranges::input_range<std::ranges::range_value_t<Range>>)
constexpr auto recursive_print(const Range& input, const int level = 0)
{
auto output = input;
std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
std::ranges::transform(std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output),
[level](auto&& element)
{
return recursive_print(element, level + 1);
}
);
return output;
}
// recursive_size implementation
template<class T> requires (!std::ranges::range<T>)
constexpr auto recursive_size(const T& input)
{
return 1;
}
template<std::ranges::range Range> requires (!(std::ranges::input_range<std::ranges::range_value_t<Range>>))
constexpr auto recursive_size(const Range& input)
{
return std::ranges::size(input);
}
template<std::ranges::range Range> requires (std::ranges::input_range<std::ranges::range_value_t<Range>>)
constexpr auto recursive_size(const Range& input)
{
return std::transform_reduce(std::ranges::begin(input), std::end(input), std::size_t{}, std::plus<std::size_t>(), [](auto& element) {
return recursive_size(element);
});
}
// recursive_reduce implementation
// Reference: https://codereview.stackexchange.com/a/251310/231235
template<class T, class ValueType, class Function = std::plus<ValueType>>
constexpr auto recursive_reduce(const T& input, ValueType init, const Function& f)
{
return f(init, input);
}
template<std::ranges::range Container, class ValueType, class Function = std::plus<ValueType>>
constexpr auto recursive_reduce(const Container& input, ValueType init, const Function& f = std::plus<ValueType>())
{
for (const auto& element : input) {
auto result = recursive_reduce(element, ValueType{}, f);
init = f(init, result);
}
return init;
}
template<typename T>
concept is_recursive_reduceable = requires(T x)
{
recursive_reduce(x, T{});
};
template<typename T>
concept is_recursive_sizeable = requires(T x)
{
recursive_size(x);
};
// arithmetic_mean implementation
template<class T = double, is_recursive_sizeable Container>
constexpr auto arithmetic_mean(const Container& input)
{
if (recursive_size(input) == 0) // Check the case of dividing by zero exception
{
throw std::logic_error("Divide by zero exception"); // Handle the case of dividing by zero exception
}
return (recursive_reduce(input, T{})) / (recursive_size(input));
}
// recursive_invoke_result_t implementation
template<typename, typename>
struct recursive_invoke_result { };
template<typename T, std::invocable<T> F>
struct recursive_invoke_result<F, T> { using type = std::invoke_result_t<F, T>; };
template<typename F, template<typename...> typename Container, typename... Ts>
requires (
!std::invocable<F, Container<Ts...>>&&
std::ranges::input_range<Container<Ts...>>&&
requires { typename recursive_invoke_result<F, std::ranges::range_value_t<Container<Ts...>>>::type; })
struct recursive_invoke_result<F, Container<Ts...>>
{
using type = Container<typename recursive_invoke_result<F, std::ranges::range_value_t<Container<Ts...>>>::type>;
};
template<typename F, typename T>
using recursive_invoke_result_t = typename recursive_invoke_result<F, T>::type;
// recursive_transform implementation
template <class T, std::invocable<T> F>
constexpr auto recursive_transform(const T& input, const F& f)
{
return f(input);
}
template <
std::ranges::input_range Range,
class F>
requires (!std::invocable<F, Range>)
constexpr auto recursive_transform(const Range& input, const F& f)
{
recursive_invoke_result_t<F, Range> output{};
std::ranges::transform(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
[&f](auto&& element) { return recursive_transform(element, f); }
);
return output;
}
// recursive_copy_if function
template <std::ranges::input_range Range, std::invocable<std::ranges::range_value_t<Range>> UnaryPredicate>
constexpr auto recursive_copy_if(const Range& input, const UnaryPredicate& unary_predicate)
{
Range output{};
std::ranges::copy_if(std::ranges::cbegin(input), std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
unary_predicate);
return output;
}
template <
std::ranges::input_range Range,
class UnaryPredicate>
requires (!std::invocable<UnaryPredicate, std::ranges::range_value_t<Range>>)
constexpr auto recursive_copy_if(const Range& input, const UnaryPredicate& unary_predicate)
{
Range output{};
std::ranges::transform(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
[&unary_predicate](auto&& element) { return recursive_copy_if(element, unary_predicate); }
);
return output;
}
// recursive_transform_reduce implementation
template<class Input, class T, class UnaryOp, class BinaryOp = std::plus<T>>
constexpr auto recursive_transform_reduce(const Input& input, T init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<T>())
{
return binop(init, unary_op(input));
}
template<std::ranges::range Input, class T, class UnaryOp, class BinaryOp = std::plus<T>>
constexpr auto recursive_transform_reduce(const Input& input, T init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<T>())
{
return std::transform_reduce(std::ranges::begin(input), std::end(input), init, binop, [&](auto& element) {
return recursive_transform_reduce(element, T{}, unary_op, binop);
});
}
// With execution policy
template<class ExPo, class Input, class T, class UnaryOp, class BinaryOp = std::plus<T>>
//requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr auto recursive_transform_reduce(ExPo execution_policy, const Input& input, T init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<T>())
{
return binop(init, unary_op(input));
}
template<class ExPo, std::ranges::range Input, class T, class UnaryOp, class BinaryOp = std::plus<T>>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr auto recursive_transform_reduce(ExPo execution_policy, const Input& input, T init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<T>())
{
return std::transform_reduce(execution_policy, std::ranges::begin(input), std::end(input), init, binop, [&](auto& element) {
return recursive_transform_reduce(execution_policy, element, T{}, unary_op, binop);
});
}
template<typename T>
concept can_calculate_variance_of = requires(const T & value)
{
(std::pow(value, 2) - value) / std::size_t{ 1 };
};
template<typename T>
struct recursive_iter_value_t_detail
{
using type = T;
};
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
: recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };
template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;
// population_variance function implementation (with recursive_transform_reduce template function)
template<class T = double, is_recursive_sizeable Container>
requires (can_calculate_variance_of<recursive_iter_value_t<Container>>)
constexpr auto population_variance(const Container& input)
{
if (recursive_size(input) == 0) // Check the case of dividing by zero exception
{
throw std::logic_error("Divide by zero exception"); // Handle the case of dividing by zero exception
}
auto mean = arithmetic_mean<T>(input);
return recursive_transform_reduce(std::execution::par,
input, T{}, [mean](auto& element) {
return std::pow(element - mean, 2);
}, std::plus<T>()) / recursive_size(input);
}
// population_standard_deviation implementation
template<class T = double, is_recursive_sizeable Container>
requires (can_calculate_variance_of<recursive_iter_value_t<Container>>)
constexpr auto population_standard_deviation(const Container& input)
{
if (recursive_size(input) == 0) // Check the case of dividing by zero exception
{
throw std::logic_error("Divide by zero exception"); // Handle the case of dividing by zero exception
}
return std::pow(population_variance(input), 0.5);
}
template<std::size_t dim, class T>
constexpr auto n_dim_vector_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_vector_generator<dim - 1>(input, times);
std::vector<decltype(element)> output(times, element);
return output;
}
}
template<std::size_t dim, std::size_t times, class T>
constexpr auto n_dim_array_generator(T input)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_array_generator<dim - 1, times>(input);
std::array<decltype(element), times> output;
std::fill(std::ranges::begin(output), std::ranges::end(output), element);
return output;
}
}
template<std::size_t dim, class T>
constexpr auto n_dim_deque_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_deque_generator<dim - 1>(input, times);
std::deque<decltype(element)> output(times, element);
return output;
}
}
template<std::size_t dim, class T>
constexpr auto n_dim_list_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_list_generator<dim - 1>(input, times);
std::list<decltype(element)> output(times, element);
return output;
}
}
template<std::size_t dim, template<class...> class Container = std::vector, class T>
constexpr auto n_dim_container_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
return Container(times, n_dim_container_generator<dim - 1, Container, T>(input, times));
}
}
void batch_recursive_count_if_test1();
int main()
{
batch_recursive_count_if_test1();
return 0;
}
void batch_recursive_count_if_test1()
{
// std::vector<std::vector<int>> case
std::cout << "std::vector<std::vector<int>> case:" << 'n';
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 lambda expressions to count the elements which is equal to 1 to 10.
auto predicator1 = [](auto& i) {return i == 1; };
std::cout << "#number is 1: " << recursive_count_if<2>(test_vector2, predicator1) << 'n';
auto predicator2 = [](auto& i) {return i == 2; };
auto predicator3 = [](auto& i) {return i == 3; };
auto predicator4 = [](auto& i) {return i == 4; };
auto predicator5 = [](auto& i) {return i == 5; };
auto predicator6 = [](auto& i) {return i == 6; };
auto predicator7 = [](auto& i) {return i == 7; };
auto predicator8 = [](auto& i) {return i == 8; };
auto predicator9 = [](auto& i) {return i == 9; };
auto predicator10 = [](auto& i) {return i == 10; };
auto batch_output1 = batch_recursive_count_if<2>(test_vector2, predicator1, predicator2, predicator3, predicator4, predicator5, predicator6, predicator7, predicator8, predicator9, predicator10);
std::cout << "Each element in batch_output1: " << 'n';
for (auto& element : batch_output1)
{
std::cout << element << 'n';
}
std::cout << 'n';
// std::deque<std::deque<int>> case
std::cout << "std::deque<std::deque<int>> case:" << 'n';
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 lambda expressions to count the elements which is equal to 1 to 10.
std::cout << "#number is 1: " << recursive_count_if<2>(test_deque2, predicator1) << 'n';
auto batch_output2 = batch_recursive_count_if<2>(test_deque2, predicator1, predicator2, predicator3, predicator4, predicator5, predicator6, predicator7, predicator8, predicator9, predicator10);
std::cout << "Each element in batch_output1: " << 'n';
for (auto& element : batch_output2)
{
std::cout << element << 'n';
}
std::cout << 'n';
// std::vector<std::vector<std::string>> case
std::cout << "std::vector<std::vector<std::string>>:" << 'n';
std::vector<std::vector<std::string>> v = { {"hello"}, {"world"} };
auto is_hello = [](auto& i) { return i == "hello"; };
auto is_world = [](auto& i) { return i == "world"; };
std::cout << "recursive_count_if output of is_hello:" << recursive_count_if<2>(v, is_hello) << std::endl;
auto batch_output3 = batch_recursive_count_if<2>(v, is_hello, is_world);
std::cout << "Each element in batch_output1: " << 'n';
for (auto& element : batch_output3)
{
std::cout << element << 'n';
}
std::cout << 'n';
// Count specific std::vector<std::vector<int>> element in std::vector<std::vector<std::vector<int>>> case
std::cout << "Count specific std::vector<std::vector<int>> element in std::vector<std::vector<std::vector<int>>> case:" << std::endl;
std::vector<decltype(test_vector2)> test_vector3;
for (size_t i = 0; i < 3; i++)
{
test_vector3.push_back(test_vector2);
}
auto batch_output4 = batch_recursive_count_if<1>(test_vector3,
[test_vector2](auto& element)
{
if (element.size() != test_vector2.size())
{
return false;
}
return std::equal(element.begin(), element.end(), test_vector2.begin());
},
[test_vector2](auto& element)
{
auto vector_for_comparison = test_vector2;
vector_for_comparison.push_back(std::vector<int>{12, 2, 3});
if (element.size() != vector_for_comparison.size())
{
return false;
}
return std::equal(vector_for_comparison.begin(), vector_for_comparison.end(), vector_for_comparison.begin());
});
for (auto& element : batch_output4)
{
std::cout << element << 'n';
}
std::cout << 'n';
return;
}
Все предложения приветствуются.
Сводная информация:
На какой вопрос это продолжение?
Функция recursive_count_if для произвольной вложенной итерируемой реализации произвольного типа в C ++ и
Функция recursive_count_if с уровнем распаковки для произвольной вложенной итерируемой реализации произвольного типа в C ++
Какие изменения были внесены в код с момента последнего вопроса?
Функция
batch_recursive_count_if
реализован здесь.Почему запрашивается новый обзор?
Я знаю, что код повторяется, но он просто решает задачу пакетного выполнения нескольких предикатов. Если есть какие-либо предложения по поводу этой реализации, дайте мне знать.