In the for
loop in the following code snippet I'm trying to apply views::filter
. But it results in type miss match and assignment error.
#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; });
}
}
Error C2679 binary '=': no operator found which takes a right-hand operand of type 'ranges::filter_viewranges::filter_view<ranges::ref_view<std::vector<int,std::allocator<int>>,Arg>,main::<lambda_2>>' (or there is no acceptable conversion)`
So basically how can I apply views::filter
on numbers
,assign the result in results
, then apply views::filter
on results
and then again assign the result in 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; });
CodePudding user response:
In your example, the return type of results | ranges::views::filter
is different from results
, so you cannot assign it to results
.
The alternative is to use ranges::to
to convert each result into a vector
and assign it to the previous result:
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;
CodePudding user response:
views::filter
returns a different type than the range type passed in. You could apply ranges::to
to create a vector after you filter each time, but this is going to be expensive. For this problem, i.e. generating primes using a sieve, it makes sense to use an eager algorithm.
The first filter you've applied is unnecessary; just start the iota
at 2, since that's the first prime.
auto results = numbers;
Then while there are still primes to sieve
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));
The above loop is doing a filter as well, but using remove
, so the condition has to be negated. Also, since the prime itself is skipped, the lambda doesn't need to check if n == i
.