Home > OS >  how to set filter from another view?
how to set filter from another view?

Time:02-17

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

I want to get the values in v1 with the condition v2=3

my desired result [4,1]

I tried with filter but it seems to work only with a specified value.

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

How can I do this without using for-loop?

CodePudding user response:

Should be something along these lines:

  • zip v1 and v2,
  • filter based on the .second of each element with the condition you like
  • transform to only retain the .first of the survived elements

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]
}

Some improvement

Notice that [](auto pair){ return pair.first; } is simply a lambda that runs std::get<0> on its input std::pair.

Unfortunately std::get<0> can't stand on its own, because there are several overlods of it (for std::pair, std::tuple, std::array, std::variant).

One way to streamline the code would be to

#include <boost/hof/lift.hpp>

and then define

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

so that you can pass get<0> around easily.

Given this, and with the help of boost::hana::compose and boost::hana::curry one can write this a curried version of std::equal_to<>{}

    auto constexpr equal_to = curry<2>(std::equal_to<>{});

and come up with this:

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

Barry pointed out in a comment that transform(get<0>) is actually ranges::views::keys, so the code can be further simplified:

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

In another comment was pointed out something that I never think about: filter takes a projection function too, so filter(compose(equal_to(3), get<1>)) does the same job as filter(equal_to(3), get<1>):

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

And finally, get<1> is elements<1> (wherever that is, I haven't found it yet :D), so we can do without Boost.Hof's BOOST_HOF_LIFT macro.

  • Related