2016-03-17 12 views
5

Ho una semplice funzione flatmap implementata in C++ per std::vector, ma è stato suggerito che gli intervalli sono generalmente migliori. Ecco la soluzione basata vettore:Come implementare la flatmap utilizzando gli intervalli 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; 
}; 

E 'stato anche suggerito che io uso iteratori, ma che rompe il bel componibilità della funzione:

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

Parto dal presupposto che in un mondo gamma-v3 sarei puntando per la scrittura di quanto sopra come:

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

Ci si sente come flatmap dovrebbe essere solo una combinazione banale di views::for_each, yield_from e transform, ma non riesco a capire come collegarli tutti insieme.

risposta

1

Se ho capito bene, che la funzione flatmap deve fare, qui è esempio di fare con le gamme:

#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, la funzione flatmap non è altro che gamma-v3 di view::for_each. Prova:

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

HTH

Problemi correlati