Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way to iterate conditionally forwards or reversed

I have to process an std::vector either forwards or in reverse, depending upon a boolean flag. What's the most elegant way to accomplish this? Before needing to do it in reverse I had:

BOOST_FOREACH(const CType &foo, vec) {
    ...
}

However, now I have the horrendous-looking:

for (int i=undoing ? (vec.size()-1) : 0; undoing ? (i >= 0) : (i < vec.size()); undoing ? (i--) : (i++)) {
    const CType &foo = vec[i];
    ...
}

Is there a better way?

like image 939
Claudiu Avatar asked Apr 15 '14 20:04

Claudiu


3 Answers

I don't know that people would call it elegant, but there's:

auto do_it = [](const CType& elem)
             {
                 ...
             };
if (iterate_forward) {
    std::for_each(vec.begin(), vec.end(), do_it);
}
else {
    std::for_each(vec.rbegin(), vec.rend(), do_it);
}
like image 57
Max Lybbert Avatar answered Sep 21 '22 07:09

Max Lybbert


Add a template function that works with either the forward iterators or reverse iterators. Call the function using the appropriate iterator based on the value of undoing.

template <typename Iterator>
void doStuff(Iterator iter, Iterator end)
{
   for ( ; iter != end; ++iter )
   {
      // Do stuff
   }
}

if ( undoing )
{
   doStuff(vec.rbegin(), vec.rend());
}
else
{
   doStuff(vec.begin(), vec.end());
}
like image 43
R Sahu Avatar answered Sep 20 '22 07:09

R Sahu


How about keeping the loop running as it is from 0 to vector.size, but reading the array in the direction you need.

int idx;
for (int i =0; i < vec.size(); i ++)
{
   if (undoing) // assuming going forward
     idx = i;
   else // going backwards
     idx = vec.size() - i - 1;

  const CType &foo = vec[idx];
}
like image 23
Naveed Avatar answered Sep 22 '22 07:09

Naveed