Distro
Distro

Reputation: 13

Count the number of elements of a vector that satisfy a predicate

For example, I have the following elements.

vector<int> n = {10, 20, 50, 35, 40, 48, 100};

If I wanted to count how many elements exist within the range of 1 to 30, the answer will be 2 since 10 and 20 is within the 1 to 30 range.

I can do it like this:

vector<int> n = {10, 20, 50, 35, 40, 48, 100};

int counter=0;
for(int x:n){
   if(x>=1 && x<=30) 
     counter++;
}

But is there a way to express the intent more clearly?

Upvotes: 1

Views: 769

Answers (5)

DailyLearner
DailyLearner

Reputation: 2374

You can use a functor to build a generic solution wherein you don't have to hard code the range.

#include <algorithm>
#include <iostream>
#include <vector>

struct RangeChecker
{
    RangeChecker(int min, int max)
    : min_{min}
    , max_{max}
    {}  

    bool operator()(int value)
    {
        return value >= min_ && value <= max_;
    }
private:
int min_;
int max_;
};

int main()
{
    std::vector<int> n = {10, 20, 50, 35, 40, 48, 100};

    int count = std::ranges::count_if(n, RangeChecker(1, 30));
    std::cout << "count = " << count << std::endl;

    int count2 = std::ranges::count_if(n, RangeChecker(1, 50));
    std::cout << "count2 = " << count2 << std::endl;

    int count3 = std::ranges::count_if(n, RangeChecker(51, 100));
    std::cout << "count3 = " << count3 << std::endl;
}

This will produce the following output:

count = 2
count2 = 6
count3 = 1

Upvotes: 0

tanmoy
tanmoy

Reputation: 1438

But is there a better way?

A better way in terms of simplicity, maybe no as it is already simple enough. But in case you are looking for a computationally efficient solution you can use binary search on sorted input.

int main() {
    vector<int> n = {0, 10, 20, 30, 50, 35, 40, 48, 100};
    sort(n.begin(), n.end());
    auto left = lower_bound(n.begin(), n.end(), 1);
    auto right = upper_bound(n.begin(), n.end(), 30);
    auto count = right - left; // your answer
    return count;
}

Upvotes: 2

Juan Medina
Juan Medina

Reputation: 593

This is in functional style for C++ 20

#include <iostream>

#include <vector>
#include <algorithm>

auto is_in_range(int min, int max) {
    return [min, max](int x) { return x >= min && x <= max; };
}

auto in_range(std::vector<int> v, int min, int max) {
    return std::count_if(v.begin(), v.end(), is_in_range(min, max));
}

int main() {
    auto int_vec = std::vector<int>{10, 20, 50, 35, 40, 48, 100};

    std::cout << "count:" << in_range(int_vec, 10, 20) << std::endl;
    std::cout << "count:" << in_range({1, 2, 3, 4}, 2, 4) << std::endl;
    std::cout << "count:" << in_range({6, 9}, 0, 1) << std::endl;

    return 0;
}

output

count:2
count:3
count:0

you can just run it here

Upvotes: 0

chrysante
chrysante

Reputation: 2846

In case your input data is unsorted your solution is correct, you can however rewrite it using the more explicit std::count_if:

int result = std::count_if(n.begin(), n.end(), [](int x) { return x>=1 && x<=30; });

Upvotes: 2

digby280
digby280

Reputation: 899

There's nothing wrong with your code. If you are looking for fewer lines of code, and you are using C++20, you can do something like this:

#include <algorithm>
#include <iostream>
#include <vector>
 
int main()
{
    std::vector<int> n = {10, 20, 50, 35, 40, 48, 100};
 
    int counter = std::ranges::count_if(n, [](int x){return x >= 1 && x <= 30;});
    std::cout << counter << std::endl;
}

Upvotes: 3

Related Questions