如何从另一个视图设置过滤器?

how to set filter from another view?

std::vector v1 {4,2,7,6,4,1};
std::vector v2 {3,0,0,0,0,3};

我想获取 v1 中的值,条件为 v2=3

我想要的结果 [4,1]

我试过使用过滤器,但它似乎只适用于指定的值。

auto rng = v1 | ranges::views::filter([](int x){return ...;});

如果不使用 for 循环,我如何做到这一点?

应该是这样的:

  • zip v1v2,
  • filter根据每个元素的.second加上你喜欢的条件
  • transform 只保留存活元素的 .first

Here's a working demo:

#include <iostream>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/zip.hpp>

using namespace ranges::views;

int main() {
    std::vector v1 {4,2,7,6,4,1};
    std::vector v2 {3,0,0,0,0,3};
    auto result = zip(v1, v2) | filter([](auto pair){ return pair.second == 3; })
                              | transform([](auto pair){ return pair.first; });
    std::cout << result << std::endl; // prints [4,1]
}

一些改进

请注意 [](auto pair){ return pair.first; } 只是一个在其输入 std::pair 上运行 std::get<0> 的 lambda。

不幸的是std::get<0>不能独立存在,因为它有几个重叠部分(对于std::pairstd::tuplestd::arraystd::variant).

简化代码的一种方法是

#include <boost/hof/lift.hpp>

然后定义

template<std::size_t N>
auto constexpr get = BOOST_HOF_LIFT(std::get<N>);

以便您可以轻松地通过 get<0>

鉴于此,在 boost::hana::compose and boost::hana::curry 的帮助下,可以将此写成 std::equal_to<>{}

的柯里化版本
    auto constexpr equal_to = curry<2>(std::equal_to<>{});

然后想出这个:

    auto result = zip(v1, v2) | filter(compose(equal_to(3), get<1>))
                              | transform(get<0>);

Barry在评论中指出transform(get<0>)其实就是ranges::views::keys,所以代码可以进一步简化:

    auto result = zip(v1, v2) | filter(compose(equal_to(3), get<1>))
                              | keys;

在另一条评论中指出了一些我从未想过的事情:filter 也有一个投影函数,所以 filter(compose(equal_to(3), get<1>))filter(equal_to(3), get<1>) 做同样的工作:

    auto result = zip(v1, v2) | filter(equal_to(3), get<1>)
                              | keys;

最后,get<1>elements<1>(不管是什么地方,我还没有找到它 :D),所以我们可以不用 Boost.Hof 的 BOOST_HOF_LIFT 宏.