首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Flatmap实现

Flatmap实现
EN

Code Review用户
提问于 2016-03-16 23:38:32
回答 1查看 3K关注 0票数 3

我有一个用于std::vector的平台图的实现。然而,我发现推断返回类型的重复是丑陋的。而且,总的来说,我怀疑实施可能更干净,或者更笼统。

代码语言:javascript
复制
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;
};

它可以这样使用:

代码语言:javascript
复制
TEST_F(MarkdownUtilTests, testFlatmap) {
    std::vector<int> v = { 1, 2, 3};
    std::vector<int> result = flatmap(v, [](int x) { return std::vector<int> { x, x*2, x*3 }; } );
    assertThat(result, is(std::vector<int> {1,2,3,2,4,6,3,6,9} ));
}
EN

回答 1

Code Review用户

发布于 2016-03-17 00:36:25

标准库中的算法使用迭代器而不是直接处理容器是有原因的。其中之一是它使这样的代码变得非常简单。例如,使用迭代器,我们可以编写类似于以下内容的Flatmap

代码语言:javascript
复制
template <typename InIter, typename OutIter, typename FN>
void Flatmap(InIter begin, InIter end, OutIter out, FN fn) {
    for (; begin != end; ++begin) {
        auto y = fn(*begin);
        std::copy(std::begin(y), std::end(y), out);
    }
}

这有点更通用,因为它可以将输入从/写输出接收到本质上的任何迭代器,而不一定要从一个向量读取并生成另一个向量。同样,fn产生的东西也不一定是向量--它本质上可以是任何容器(更准确地说,我们可以使用std::begin()std::end() )。虽然向量是常见的,但使用其他容器是有原因的--有时甚至有理由写到不完全是容器的东西上。例如:

代码语言:javascript
复制
std::vector<int> inputs { 1, 2, 3 };

Flatmap(inputs.begin(), inputs.end(), 
        std::ostream_iterator<int>(std::cout, "\t"), 
        [](auto x) { return std::vector<decltype(x)> { x, x * 2, x * 3 }; });

注意,我在lambda中使用了auto作为参数类型,所以这个测试代码需要C++14,但是Flatmap本身在C++11中很好。

如果您想要有更多的前瞻性思考,您可以编写它来处理范围而不是迭代器。埃里克·内布勒的范围库相当不错,而且在即将推出的C++标准中似乎还不错。

随着代码更简单、更通用,另一个明显的优点是它遵循与标准库代码相同的样式--例如,它的签名和使用与std::transform本质上是相同的。

票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/123053

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档