How to implement a flat card with rangev3 range

I have a fairly simple flatmap function implemented in C ++ for std::vector , but it has been suggested that ranges are usually better. Here's a vector solution:

 // flatmap: [A] -> (A->[B]) -> [B] template<typename T, typename FN> static auto flatmap(const std::vector<T> &vec, FN fn) -> std::vector<typename std::remove_reference<decltype(fn(T())[0])>::type> { std::vector<typename std::remove_reference<decltype(fn(T())[0])>::type> result; for(auto x : vec) { auto y = fn(x); for( auto v : y ) { result.push_back(v); } } return result; }; 

It has also been suggested that I use iterators, but this violates the nice composition of the function:

 map(filter(flatmap( V, fn), fn2), fn3) 

I would suggest that in the world of range-v3, I would like to write above:

 auto result = v | flatmap(fn) | filter(fn2) | transform(fn3); 

It seems like flatmap should just be a trivial combination of views::for_each , yield_from and transform , but I'm struggling to figure out how to link them all together.

+5
source share
2 answers

IIUC, your flatmap function is nothing more than range-v3 view::for_each . Try:

using namespace ranges; auto result = v | view::for_each(fn) | to_vector;

NTN

+5
source

If I understood correctly what your flatmap function should do, here is an example of its creation with ranges:

 #include <range/v3/all.hpp> #include <iostream> #include <string> #include <utility> #include <vector> // flatmap: [A] -> (A->[B]) -> [B] template<typename T, typename FN> static auto flatmap(const std::vector<T> &vec, FN fn) -> std::vector<typename std::remove_reference<decltype(fn(T())[0])>::type> { std::vector<typename std::remove_reference<decltype(fn(T())[0])>::type> result; for(auto x : vec) { auto y = fn(x); for( auto v : y ) { result.push_back(v); } } return result; }; // This will be test function for both flatmap and range usage std::vector<std::string> testFn(int n) { std::vector<std::string> result; int ofs = 0; for(int i = 0; i < n; ++i) { char initialChar = 'A' + ofs; std::string partialResult = "\""; for(int j = 0; j <=i; ++j, ++ofs) { partialResult.append(1, initialChar+j); } partialResult += "\""; result.push_back(partialResult); } return std::move(result); } int main(int, char**) { std::vector<int> vv {1, 2, 3, 4, 5, 6}; // test flatmap auto r2 = flatmap(vv, testFn); for(auto s:r2) { std::cout << s << " " ; } std::cout << "\n"; using namespace ranges; // test ranges equivalent auto rng = vv|view::transform(testFn)|action::join; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is an equivalent for flatmap in ranges terms for(auto s:rng) { std::cout << s << " "; } std::cout << "\n"; std::cout << std::flush; return 0; } 
+1
source

Source: https://habr.com/ru/post/1245211/


All Articles