【问题标题】:Iteratively apply range-v3 views::filter on a container在容器上迭代地应用 range-v3 views::filter
【发布时间】:2021-11-18 12:06:22
【问题描述】:

在以下代码 sn-p 的for 循环中,我正在尝试应用views::filter。但是会导致类型不匹配和赋值错误。

#include <iostream>
#include <vector>
#include <numeric>
#include <range/v3/all.hpp>

int main()
{
    int limit =100;
    std::vector<int> numbers(100);
    std::iota(numbers.begin(), numbers.end(), 1);
    auto results = numbers | ranges::views::filter([](int n) {return n != 1; });
                           
    int sqrt_limit = std::sqrt(limit);
    for (int i = 2; i <= sqrt_limit; i++)
    {
        results = results | ranges::views::filter([i](int n) {return n == i
            || n % i != 0; });
    }
}

错误 C2679 二进制“=”:未找到采用“ranges::filter_viewranges::filter_view<:ref_view> 类型的右侧操作数的运算符>,Arg>,main::>' (或没有可接受的转换)`



所以基本上我怎样才能在numbers上应用views::filter,在results上分配结果,然后在results上应用views::filter,然后再次在results上分配结果?

std::vector<int> numbers(100);
std::iota(numbers.begin(), numbers.end(), 1);
auto results = numbers | ranges::views::filter([](int n) {return n != 1; });
results = results | ranges::views::filter([i](int n) {return n == 2
        || n % 2 != 0; });

【问题讨论】:

    标签: c++ functional-programming c++20 range-v3


    【解决方案1】:

    在您的示例中,results | ranges::views::filter 的返回类型与results 不同,因此您不能将其分配给results

    另一种方法是使用ranges::to 将每个结果转换为vector 并将其分配给之前的结果:

    std::vector<int> numbers(100);
    std::iota(numbers.begin(), numbers.end(), 1);
    auto results = numbers
                 | ranges::views::filter([](int n) {return n != 1; })
                 | ranges::to_vector;
    results = results
            | ranges::views::filter([](int n) {return n == 2|| n % 2 != 0; })
            | ranges::to_vector;
    

    Demo.

    【讨论】:

    • 谢谢。我不知道 range::to .
    【解决方案2】:

    views::filter 返回的类型与传入的范围类型不同。您可以在每次过滤后应用ranges::to 创建一个向量,但这会很昂贵。对于这个问题,即使用筛子生成素数,使用 Eager 算法是有意义的。

    您应用的第一个过滤器是不必要的;只需在 2 处开始 iota,因为那是第一个素数。

    auto results = numbers;
    

    那么当还有素数要筛选的时候

    auto end = std::end(results);
    for (auto begin = std::begin(results); begin != end; begin++)
        end = std::remove_if(begin + 1, end,        // *begin is prime by definition, so skip it
                             [i = *begin](int n) {
                                return n % i == 0;  // remove multiples of the prime 
                                });
    
    // erase all the composite numbers
    results.erase(end, std::end(results));
    

    上面的循环也在做一个过滤器,但是使用remove,所以这个条件必须被否定。此外,由于跳过了素数本身,因此 lambda 不需要检查是否为 n == i

    demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 2020-02-07
      • 2019-08-09
      • 2016-03-30
      • 1970-01-01
      相关资源
      最近更新 更多