9

flatmap私はC++ で実装された非常に単純な関数を持っstd::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;
};

イテレータを使用することも提案されていますが、それは関数の素晴らしい構成可能性を壊します:

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

range-v3 の世界では、上記を次のように書くことを目指していると思います。

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

flatmap、 の些細な組み合わせであるべきだと思いますが、それらをすべて組み合わせる方法を見つけるのに苦労しています。views::for_eachyield_fromtransform

4

3 に答える 3

2

私が正しく理解していれば、あなたの関数が何をflatmapしなければならないか、あなたはそれを次のように書くことができますv | view::transform(fn) | action::join. 範囲で作成する例を次に示します。

#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;
}
于 2016-03-17T10:52:50.947 に答える