holianoify
holianoify

Reputation: 33

Applying conditions to the whole vector

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

Answers (3)

James Kanze
James Kanze

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

Emilio Garavaglia
Emilio Garavaglia

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

P0W
P0W

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

Related Questions