I have a collection of elements that I need to operate over, calling member functions on the collection:
std::vector<MyType> v;
... // vector is populated
For calling functions with no arguments it's pretty straight-forward:
std::for_each(v.begin(), v.end(), std::mem_fun(&MyType::myfunc));
A similar thing can be done if there's one argument to the function I wish to call.
My problem is that I want to call a function on elements in the vector if it meets some condition. std::find_if returns an iterator to the first element meeting the conditions of the predicate.
std::vector<MyType>::iterator it =
std::find_if(v.begin(), v.end(), MyPred());
I wish to find all elements meeting the predicate and operate over them.
I've been looking at the STL algorithms for a "find_all" or "do_if" equivalent, or a way I can do this with the existing STL (such that I only need to iterate once), rather than rolling my own or simply do a standard iteration using a for loop and comparisons.
Boost Lambda makes this easy.
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/if.hpp>
std::for_each( v.begin(), v.end(),
if_( MyPred() )[ std::mem_fun(&MyType::myfunc) ]
);
You could even do away with defining MyPred(), if it is simple. This is where lambda really shines. E.g., if MyPred meant "is divisible by 2":
std::for_each( v.begin(), v.end(),
if_( _1 % 2 == 0 )[ std::mem_fun( &MyType::myfunc ) ]
);
Update:
Doing this with the C++0x lambda syntax is also very nice (continuing with the predicate as modulo 2):
std::for_each( v.begin(), v.end(),
[](MyType& mt ) mutable
{
if( mt % 2 == 0)
{
mt.myfunc();
}
} );
At first glance this looks like a step backwards from boost::lambda syntax, however, it is better because more complex functor logic is trivial to implement with c++0x syntax... where anything very complicated in boost::lambda gets tricky quickly. Microsoft Visual Studio 2010 beta 2 currently implements this functionality.
I wrote a for_each_if() and a for_each_equal() which do what I think you're looking for.
for_each_if() takes a predicate functor to evaluate equality, and for_each_equal() takes a value of any type and does a direct comparison using operator ==. In both cases, the function you pass in is called on each element that passes the equality test.
/* ---
For each
25.1.1
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f)
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f)
Requires:
T is of type EqualityComparable (20.1.1)
Effects:
Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold:
1: *i == value
2: pred(*i) != false
Returns:
f
Complexity:
At most last - first applications of f
--- */
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first,
InputIterator last,
Predicate pred,
Function f)
{
for( ; first != last; ++first)
{
if( pred(*first) )
f(*first);
}
return f;
};
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first,
InputIterator last,
const T& value,
Function f)
{
for( ; first != last; ++first)
{
if( *first == value )
f(*first);
}
return f;
};
Is it ok to change the vector? You may want to look at the partition algorithm.
Partition algorithm
Another option would be to change your MyType::myfunc to either check the element, or to take a predicate as a parameter and use it to test the element it's operating on.
std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin();
MyPred my_pred;
while(true) {
i = std::find_if(i, v.end(), my_pred);
if (i == v.end())
break;
matches.push_back(*i);
}
For the record, while I have seen an implementation where calling end() on a list was O(n), I haven't seen any STL implementations where calling end() on a vector was anything other than O(1) -- mainly because vectors are guaranteed to have random-access iterators.
Even so, if you are worried about an inefficient end(), you can use this code:
std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin(), end = v.end();
MyPred my_pred;
while(true) {
i = std::find_if(i, v.end(), my_pred);
if (i == end)
break;
matches.push_back(*i);
}
For what its worth for_each_if is being considered as an eventual addition to boost. It isn't hard to implement your own.
Lamda functions - the idea is to do something like this
for_each(v.begin(), v.end(), [](MyType& x){ if (Check(x) DoSuff(x); })
Origial post here.
You can use Boost.Foreach:
BOOST_FOREACH (vector<...>& x, v)
{
if (Check(x)
DoStuff(x);
}
Related
What is time complexity for std::find_if() function using std::set in C++?
Consider we have the following example:
auto cmp = [&](const pair<int, set<int>>& a , const pair<int, set<int>>& b) -> bool {
if (a.second.size() == b.second.size()) {
return a.first < b.first;
}
return a.second.size() < b.second.size();
};
set<pair<int, set<int>>, decltype(cmp)> tree(cmp);
...
int value = ...;
auto it = find_if(tree.begin(), tree.end(), [](const pair<int, int> &p) {
return p.first == value;
});
I know it takes std::find_if O(n) to work with std::vector. Can't see any problems for this function not to work with std::set with time complexity O(log(n)).
The complexity for std::find, std::find_if, and std::find_if_not is O(N). It does not matter what type of container you are using as the function is basically implemented like
template<class InputIt, class UnaryPredicate>
constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first) {
if (p(*first)) {
return first;
}
}
return last;
}
Which you can see just does a linear scan from first to last
If you want to take advantage of std::set being a sorted container, then you can use std::set::find which has O(logN) complexity. You can get a find_if type of behavior by using a comparator that is transparent.
std::find_if is equal opportunity because it can't take advantage of any special magic from the container. It just iterates the container looking for a match, so worst case is always O(N).
See documentation for std::find_if starting at the section on Complexity and pay special attention to the possible implementations.
Note that std::find_if's actual performance will likely be MUCH worse with a set than that of a vector of the same size because of the lack of locality in the data stored.
This code has the Visual Studio error C3892. If I change std::set to std::vector - it works.
std::set<int> a;
a.erase(std::remove_if(a.begin(), a.end(), [](int item)
{
return item == 10;
}), a.end());
What's wrong? Why can't I use std::remove_if with std::set?
You cannot use std::remove_if() with sequences which have const parts. The sequence of std::set<T> elements are made up of T const objects. We actually discussed this question just yesterday at the standard C++ committee and there is some support to create algorithms dealing specifically with the erase()ing objects from containers. It would look something like this (see also N4009):
template <class T, class Comp, class Alloc, class Predicate>
void discard_if(std::set<T, Comp, Alloc>& c, Predicate pred) {
for (auto it{c.begin()}, end{c.end()}; it != end; ) {
if (pred(*it)) {
it = c.erase(it);
}
else {
++it;
}
}
}
(it would probably actually delegate to an algorithm dispatching to the logic above as the same logic is the same for other node-based container).
For you specific use, you can use
a.erase(10);
but this only works if you want to remove a key while the algorithm above works with arbitrary predicates. On the other hand, a.erase(10) can take advantage of std::set<int>'s structure and will be O(log N) while the algorithm is O(N) (with N == s.size()).
Starting with C++20, you can use std::erase_if for containers with an erase() method, just as Kühl explained.
// C++20 example:
std::erase_if(setUserSelection, [](auto& pObject) {
return !pObject->isSelectable();
});
Notice that this also includes std::vector, as it has an erase method. No more chaining a.erase(std::remove_if(... :)
std::remove_if re-orders elements, so it cannot be used with std::set. But you can use std::set::erase:
std::set<int> a;
a.erase(10);
What I want is this behavior: void change_if( ForwardIterator first, ForwardIterator last, UnaryPredicate test, UnaryOperation op )
Is the best way to achieve that just with a for loop? Or is there some STL magic I don't yet know?
This can be done without using boost but applying standard algorithm std::for_each
I do not advice to use boost for such simple tasks. It is simply a stupidy to include boost in your project that to perform such a simple task. You may use boost for such tasks provided that it is already included in your project.
std::for_each( first, last, []( const T &x ) { if ( test( x ) ) op( x ); } );
Or you can remove the qualifier const if you are going to change elements of the sequence
std::for_each( first, last, []( T &x ) { if ( test( x ) ) op( x ); } );
Sometimes when the whole range of a sequence is used it is simpler to use the range based for statement instead of an algorithm becuase using algorithms with lambda expressions sometimes makes code less readable
for ( auto &x : sequence )
{
if ( test( x ) ) op( x );
}
Or
for ( auto &x : sequence )
{
if ( test( x ) ) x = op( x );
}
The solution by Vlad from Moscow is the recommended approach for it's simplicity.
The "seemingly obious" use of the std::transform standard algorithm with a lambda:
std::transform(first, last, first, [](auto elem) {
return test(elem) ? op(elem) : elem;
});
actually leads to performance degradation because all elements will be assigned to, not just those satisfying the predicate. To only modify the predicated elements, one would also need something like boost::filter_iterator as mentioned in the answer by kiwi.
Note that I used C++14 syntax with the auto inside the lambda. For C++11, you would need something like decltype(*first) or iterator_traits<ForwardIterator>::value_type. And in C++98/03 you would both that and a hand made function object.
Still another boost solution :
http://www.boost.org/doc/libs/1_55_0/libs/iterator/doc/filter_iterator.html
Just call std::transform on your filtered iterator.
std::for_each( first, last, []( T &x ) { if ( test( x ) ) op( x ); } );
or using boost lambda:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/if.hpp>
std::for_each( v.begin(), v.end(),
if_( test() )[ op() ]
);
alternatively:
std::vector<int>::iterator it = v.begin();
while ( it != v.end()) {
if ( test( *it)) op(*it);
++it;
}
You want change_if as a simple loop?
template<typename ForwardIterator, typename UnaryPredicate>
void change_if( ForwardIterator first, ForwardIterator last, UnaryPredicate test, UnaryOperation op ) {
for(; first!=last; ++first)
if (test(*first)) *first=op(std::move(*first));
}
or just write the above loop. I would advise actually writing change_if and calling it, because while the above code is short I would find the change_if call to be more, not less, clear than just dropping the above code in.
I also like writing container-based overloads:
template<typename Container, typename UnaryPredicate>
void change_if( Container&& c, UnaryPredicate test, UnaryOperation op ) {
for(auto& v : std::forward<Container>(c))
if (test(v)) v=op(std::move(v));
}
but I also have this:
template<typename Iterator>
struct range {
Iterator b, e;
Iterator begin() const { return b; }
Iterator end() const { return e; }
};
template<typename Iterator0, typename Iterator1>
range<typename std::decay<Iterator0>::type> make_range(Iterator0&& b, Iterator1&& e) {
static_assert(
std::is_convertible< Iterator1, typename std::decay<Iterator0>::type >::value,
"end must be compatible with begin iterator type"
);
return { std::forward<Iterator0>(b), std::forward<Iterator1>(e) };
}
which lets me use such container-based algorithms with iterators.
You'll see I have a Container based change_if? It is really a range-based change_if.
It is called like:
change_if( myVect, [](int x){return (x%2)==0;}, [](int x){return x/2;} );
on a container, not a pair of iterators. However, if you only want to change the first half of a container, it doesn't work: so at first glance, container-based (well, range-based) algorithms are less useful.
But make_range turns iterators into a range. So you can:
change_if( make_range( myVec.begin(), myVec.begin()+myVec.size()/2 ), [](int x){return (x%2)==0;}, [](int x){return x/2;} )
make_range fills in the inability to directly pass 2 iterators to range-based algorithms by bundling two iterators into one range<> object. This corner case is more verbose, but the typical case (of processing an entire container) becomes less verbose.
Plus, a common kind of error (naming a different container for begin and end) is made far less frequent.
All of this ends up being as efficient, or more so, than the iterator-based version. And, if you replace your ranges with iterables (ranges that have dissimilar begin and end iterator types), my change_if just works
What is the C++ idiomatic way of creating a std::vector from the last n elements of a std::map?
I am not interested in preserving the order in the vector.
I can copy the elements, like this:
std::map< double, MyType > m;
size_t n = 3;
std::vector< MyType > v;
std::map< double, MyType >::iterator it = m.end();
while ( n-- ) { // assuming m.size() >= n
it--;
v.push_back(it->second);
}
But, is there any other way, more idiomatic, to do it?
std::copy would be suitable if you wanted to copy the types unchanged. However, std::map<T,U>::iterator_type::value_type is not U (the type you want to copy), but std::pair<T,U> (in other words, dereferencing a map iterator yields a pair of the key and value types), so a raw copy won't work.
So we need to copy the elements, performing a transformation along the way. That's what std::transform is for.
For convenience, I'm going to assume that your compiler supports C++11 lambda expressions and the auto keyword. If not, it can be fairly trivially rewritten as a functor. But we're looking for something roughly like this:
std::transform(map_first, map_last, std::back_inserter(vec), [](std::pair<double,MyType> p) { return p.second; });
Now we just need to fill in the two first parameters:
auto map_first = std::next(map.end(), -n);
auto map_last = map.end();
The only tricky part here is that map iterators are bidirectional, but not random-access, so we can't simply say map.end() - n. The - operator is not defined. Instead, we have to use std::next (which takes linear rather than constant time for bidirectional operators, but there's no way around that).
(Note, I haven't tried compiling this code, so it might require a small bit of tweaking)
std::transform would be the most idiomatic way. You need a functional
object:
template<typename PairType>
struct Second
{
typename PairType::second_type operator()( PairType const& obj ) const
{
return obj.second;
}
}
(If your doing much work with std::map or other things that use
std::pair, you'll have this in your toolbox.)
After that, it's a bit awkward because you only want the last n. Since
iterators into a map are not random access iterators, and you can't add
or subtract arbitrary values, the simplest solution is to copy them all,
then remove the ones you don't want:
std::vector<MyType>
extractLastN( std::map<double, MyType> const& source, size_t n )
{
std::vector<MyType> results;
std::transform( source.begin(), source.end(),
std::back_inserter( results ),
Second<std::map<double, MyType>::value_type>() );
if ( results.size() > n ) {
results.erase( results.begin(), results.end() - n );
}
return results;
}
This isn't the most efficient, but depending on n and where it is
used, it may be sufficient. If you do want to avoid the extra copying,
etc. (probably worthwhile only if n is typically much smaller than the
size of the map), you'll have to do something fancier:
std::vector<MyType>
extractLastN( std::map<double, MyType> const& source, ptrdiff_t n )
{
std::map<double, MyType>::const_iterator start
= source.size() <= n
? source.begin()
: std::prev( source.end(), n );
std::vector<MyType> results;
std::transform( start, source.end(),
std::back_inserter( results ),
Second<std::map<double, MyType>::value_type>() );
return results;
}
(If you don't have access to C++11, std::prev is simply:
template<typename IteratorType>
IteratorType
prev( IteratorType start, ptrdiff_t n )
{
std::advance( start, -n );
return start;
}
Again, if you're doing much with the standard library, you probably
already have it in your toolkit.)
Here's a simple Boost.Range version:
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/adaptor/map.hpp>
//#include <boost/range/adaptor/reversed.hpp> // comment in for 'reversed'
#include <map>
#include <vector>
struct X{};
int main(){
std::map<int, X> m;
unsigned n = 0;
auto vec(boost::copy_range<std::vector<X>>(
boost::make_iterator_range(m, m.size()-n, 0)
| boost::adaptors::map_values
//| boost::adaptors::reversed // comment in to copy in reverse order
));
}
One way of doing it is using a simple for_each:
map<int,double> m;
vector<double> v;
//Fill map
auto siter = m.end();
advance(siter, -3);
for_each(siter, m.end(), [&](pair<int,double> p) { v.push_back(p.second); });
EDIT Even simpler way is using std::prev with for_each:
map<int,double> m;
vector<double> v;
//Fill map
for_each(prev(m.end(), 3), m.end(),
[&](pair<int,double> p) { v.push_back(p.second); });
Also, if you want fill the vector in reverse order you can use:
for_each(m.rbegin(), next(m.rbegin(), 3),
[&](pair<int,double> p) { v.push_back(p.second); });
First, what do we want to write to be idiomatic? I suggest:
std::vector<Mytype> v;
v.reserve(n);
std::transform(
limited(n, m.rbegin()),
limited_end(m.rend()),
std::back_inserter(v),
values_from(m)
);
Now we just have to make that code valid.
We can replace values_from(m) with a lambda (which doesn't need m), or implement it using James Kanze's class Second (in which case m is there for type deduction):
template <typename Map>
Second<Map::value_type> values_from(const Map &) {
return Second<Map::value_type>();
}
Implementing limited is a bit of a pain. It's a template function that returns an iterator. The iterator type it returns is a template that wraps another iterator type, and forwards everything on to it except that it keeps track of n, and acts like an end iterator when it has been advanced n times. limited_end returns an end iterator of the same type, so it compares equal either if the underlying iterators are equal, or if one of the iterators was created with limited_end and the other one has run n down to zero.
I don't have the code for this handy, but it's basically how you get _n equivalents of all the standard algorithms, not just copy_n. In this case, we want transform_n, but there isn't one.
An alternative to transform would be to use copy_n with a boost::transform_iterator wrapped around m.rbegin(). I won't do that here either, because I always have to check the docs to use transform_iterator.
Do it backwards:
assert(n <= m.size());
std::copy(m.rbegin(), m.rbegin()+n, std::back_inserter(v));
bidirectional iterators FTW.
OK, I obviously wasn't awake yet, and that was wishful thinking. I still prefer walking backwards to get the last n though, so a working version looks like this:
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
// I'm assuming it's ok to copy min(m.size(), n)
template <typename Iter>
Iter safe_advance(Iter begin, Iter const &end, int distance)
{
while(distance-- > 0 && begin != end)
++begin;
return begin;
}
void copy_last_n(map<double,int> const &m,
vector<int> &v, int n)
{
transform(m.rbegin(), safe_advance(m.rbegin(), m.rend(), n),
back_inserter(v),
[](map<double,int>::value_type const &val)
{
return val.second;
}
);
}
James Kanze already wrote the Second functor - use that if you don't have access to lambdas.
While using std::for_each algorithm how do I break when a certain condition is satisfied?
You can use std::any_of (or std::all_of or std::none_of) e.g. like this:
std::vector<int> a;
// ...
std::all_of(a.begin(), a.end(), [&](int val) {
// return false if you want to break, true otherwise
});
However, this is a wasteful solution (return values are not really used for anything), and you're better off writing you own loop.
You can use std::find_if algorithm, which will stop and return the iterator to the first element where the predicate condition applied to returns true. So your predicate should be changed to return a boolean as the continue/break condition.
However, this is a hack, so you can use the algorithms.
Another way is to use BOOST_FOREACH.
You can break from the for_each() by throwing an exception from your functor. This is often not a good idea however, and there are alternatives.
You can retain state in your functor. If you detect the 'break' condition, simply set a flag in your functor and then for each subsequent iteration simply return without doing your functor's thing. Obviously this won't stop the iteration, which might be expensive for large collections, but it will at least stop the work from being performed.
If your collection is sorted, you can find() the element that you want to break at, then do for_each from begin() to the element find() returned.
Finally, you can implement a for_each_if(). This will again not stop the iteration but will not evaluate your functor which does the work if the predicate evaluates to false. Here are 2 flavors of for_each_xxx(), one which takes a value and performs the work if operator==() evaluates to true, and another which takes two functors; one which performs a comparison ala find_if(), and the other which performs the work if the comparison operator evaluates to true.
/* ---
For each
25.1.1
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f)
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f)
Requires:
T is of type EqualityComparable (20.1.1)
Effects:
Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold:
1: *i == value
2: pred(*i) != false
Returns:
f
Complexity:
At most last - first applications of f
--- */
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first,
InputIterator last,
Predicate pred,
Function f)
{
for( ; first != last; ++first)
{
if( pred(*first) )
f(*first);
}
return f;
};
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first,
InputIterator last,
const T& value,
Function f)
{
for( ; first != last; ++first)
{
if( *first == value )
f(*first);
}
return f;
};
If you want do some actions while condition is not satisfied, maybe you need change algorithm on something like std::find_if?
As already shown by others it is only achievable with workarounds that IMHO obfuscate the code.
So my suggestions is to change the for_each into a regular for loop. This will make it more visible to others that you are using break (and maybe even continue).
You can't do it, unless you throw an exception, which is not a good idea because you don't do flow control with exceptions.
Update: apparently Boost has a for_each_if that might help, but you're not using Boost.
You throw an exception. Whether or not it's a good idea is sort of a style question, pace #Dan, but may be more of an issue with your design. for_each is intended for a sort of functional-programming style, which implicitly assumes that your function can be applied uniformly across the set. So, if you do need to break, that could be consiered an unusual condition, and therefore worthy of an exception.
The other solution, and a more "functional" solution, is to write your function so that if it shouldn't have an effect on some applications, then write it to have no effect. So, for example, if you had a summing function, have it add 0 in the cases you would have "broken" from.
You can use std::find_if instead std::for_each:
int aaa[]{ 1, 2, 3, 4, 5, 6, 7, 8 };
std::find_if(aaa, std::next(aaa, sizeof(aaa) / sizeof(int)), [](const auto &i) {
if (i == 5)
return true;
std::cout << i << std::endl;
return false;
});
Output:
1
2
3
4