2016-03-17 13 views
5

Mam całkiem prostą funkcję flatmap zaimplementowaną w C++ dla std::vector, ale zasugerowano, że zakresy są ogólnie lepsze. Oto rozwiązanie wektor oparty:Jak zaimplementować mapę płaską przy użyciu zakresów rangev3

// 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; 
}; 

Stwierdzono również zasugerował, że mogę używać iteratory, ale łamie piękny composability funkcji:

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

Przypuszczam, że w świecie gama-V3 byłbym zmierzające do pisania powyższego jako:

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

czuje się jak flatmap powinny być po prostu banalne połączenie views::for_each, yield_from i transform, ale staram się dowiedzieć, jak połączyć je wszystkie razem.

Odpowiedz

1

Jeśli dobrze zrozumiałem, co się funkcja flatmap musi zrobić, tutaj jest przykładem, zarówno z zakresów:

#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; 
} 
5

IIUC, czynność flatmap jest tylko zakres-v3 view::for_each. Spróbuj:

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

HTH

Powiązane problemy