Reputation: 33
I need to have a while loop that applies a logic condition to every element of a vector.
For example, while(all elements < 3) or while(all elements != 3)
The only way I can think of is write while(vector[1]!=3 || vector[2]!=3 || ...). That would quickly grow if my vector is large.
Are there better way of doing this in C++?
Upvotes: 2
Views: 1849
Reputation: 153987
As others have said, in C++11, there are special functions for
this. In pre-C++11, the usual idiom would have involved
std::find_if
, and a comparison with the end iterator on the
results, e.g.:
struct Condition
{
// The condition here must be inversed, since we're looking for elements
// which don't meet it.
bool operator()( int value ) const { return !(value < 3); }
};
// ...
while ( std::find_if( v.begin(), v.end(), Condition() ) == v.end() ) {
// ...
}
This is such a common idiom that I continue to use it in C++11 (although often with a lambda).
Upvotes: 0
Reputation: 20759
In C++11, the answer is essentially using std::all
together with lambdas:
if (std::all(v.begin(),v.end(),[](const typename std::decay::type& a) { return a<3; }) { 7* your stuff here */ }
In C++03, you have to workout std::all and the lambdas:
template<class Iter, Fn>
bool all(Iter i, Iter end, Fn fn)
{
for(;i!=end; ++i)
if(!fn(*i)) return false;
return true;
}
and for <3
you need an explicit class like
class is_less_than_val
{
int val;
public:
is_less_than(int value) :val(value) {}
bool operator()(int var) const { return var<val; }
};
so that you can write
if(all(v.begin(),v.end(),is_less_than_val(3))
{ /* your stuff here */ }
In case you find all the functinal machinery obscure (C++03 is not that "easy", having no substantial type deduction), and prefer a more procedural approach,
template<class Cont, class Val>
bool all_less_than(const Cont& c, const Val& v)
{
for(typename Cont::const_iterator i=c.cbegin(), i!=c.end(); ++i)
if(!(*i < v)) return false;
return true;
}
template<class Cont, class Val>
bool all_equal_to(const Cont& c, const Val& v)
{
for(typename Cont::const_iterator i=c.cbegin(), i!=c.end(); ++i)
if(!(*i == v)) return false;
return true;
}
In all the samples, whatever the code is arranged, everything boils down into a loop that breaks as false on the negation of the searched condition.
Of course, if all are numerical comparison, !(<)
is >=
and !(==)
is !=
, but since Cont and Val are template parameters, using only < and == result is less requirements for Val implementation (that can be anything, not just int
)
Upvotes: 0
Reputation: 47824
See std::all_of
Assuming
std::vector<int> v;
if(std::all_of(v.cbegin(), v.cend(), [](int i){ return i < 3 }))
{
}
if(std::all_of(v.cbegin(), v.cend(), [](int i){ return i != 3 }))
{
}
Pre-C++11
struct Check
{
int d;
Check(int n) : d(n) {}
bool operator()(int n) const
{ return n < d; }
};
// Copied from above link
template< class InputIt, class UnaryPredicate >
bool all_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first) {
if (!p(*first)) {
return false;
}
}
return true ;
}
if( all_of(v.begin(), v.end(), Check(3) ))
{
}
Upvotes: 5