C ++ select algorithm

Among the functionalities found in std::algorithm , I cannot find one of the simplest that I can think of: I selected a subset of the collection (for example, return all odd numbers, all employees with status == 'used', all items less than $ 20).

So, given an int list, for example

 vector<int> ints {1, 9, 3, 27, 5, 19, 3, 8, 2, 12}; vector<int> evens = ? vector<int> greaterThan7 = ? 

How to find those that are even and those that are greater than 7?

+8
c ++ algorithm lambda vector
source share
3 answers

for example

 vector<int> ints {1, 9, 3, 27, 5, 19, 3, 8, 2, 12}; vector<int> evens; std::copy_if( ints.begin(), ints.end(), std::back_inserter( evens ), []( int x ) { return x % 2 == 0; } ); 

Here is a demo program

 #include <iostream> #include <algorithm> #include <iterator> #include <vector> int main() { std::vector<int> ints { 1, 9, 3, 27, 5, 19, 3, 8, 2, 12 }; std::vector<int> evens; std::copy_if( ints.begin(), ints.end(), std::back_inserter( evens ), []( int x ) { return x % 2 == 0; } ); for ( int x : evens ) std::cout << x << ' '; std::cout << std::endl; } 

His conclusion

 8 2 12 
+17
source share

If you want something more functional, you can check out the extended range library. In particular, filtered :

 for (int i : ints | filtered([](int i){return i > 7;})) { ... } 

This gives you a lazy view without creating a new container.


You can get the same from Eric Nibler range-v3 :

 for (int i : view::filter(ints, [](int i){return i > 7;}) { ... } 

with the advantage that you can simply assign to this vector (so you can choose whether it will be lazy or impatient, which Boost.Ranges does not allow).

 std::vector<int> greaterThan7 = view::filter(ints, [](int i){return i > 7;}); std::vector<int> sameThing = ints | view::filter([](int i){return i > 7;}); 
+19
source share

Depending on your exact requirements, consider std::stable_partition (or std::partition ). It reorders the elements in the range so that all that satisfy the predicate are first. You can think of it as dividing a range into a "subset" and "not a subset." Here is an example:

 #include <algorithm> #include <vector> #include <iostream> int main() { using std::begin; using std::end; using std::cbegin; using std::cend; std::vector<int> ints { 1, 9, 3, 27, 5, 19, 3, 8, 2, 12 }; auto const greater_than_7 = [](int number) { return number > 7; }; auto const iter_first_not_greater_than_7 = std::stable_partition(begin(ints), end(ints), greater_than_7); for (auto const_iter = cbegin(ints); const_iter != iter_first_not_greater_than_7; ++const_iter) { std::cout << *const_iter << "\n"; } } 

If, however, everything is OK with copying each corresponding item to a new collection, for example, because the original range should not be changed, then use std::copy_if .


Perhaps what you are really looking for is a representation of the unmodifiable range. In this case, you are approaching the problem from the wrong direction. You do not need a specific algorithm; A more natural solution to the problem would be filtering an iterator , such as Boost Filter Iterator . You can use it in Boost or study its implementation to find out how you can write filter iterators yourself.

+1
source share

All Articles