C++ - Iterating over std::vector<> returned from find_if

11,075

Solution 1

// find_if example
#include <iostream>     // std::cout
#include <algorithm>    // std::find_if
#include <vector>       // std::vector

bool IsOdd (int i) {
  return ((i%2)==1);
}

int main () {
  std::vector<int> myvector;

  myvector.push_back(10);
  myvector.push_back(25);
  myvector.push_back(40);
  myvector.push_back(55);


  std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd); 
  std::cout << "ODD values are: " << std::endl;     

  while(it != myvector.end() ){

    std::cout << *it  << " in position " << (it - myvector.begin())  << '\n';
    it = std::find_if (++it, myvector.end(), IsOdd); 
  }
  return 0;
}

EDIT: Changed it+1 to ++it see @David Rodríguez - dribeas comment below.

Solution 2

You can increment it and use it as a starting point to iterate further:

std::cout << "odd values: ";
auto it = myvector.begin();
while(it != myvector.end())
{
   it = std::find_if (it, myvector.end(), IsOdd);
   if(it == myvector.end()) break;
   std::cout << *it << ' ';
   ++it;
}
std::cout << endl;

A much more algorithm oriented approach, makes use of copy_if, having an output vector as a result container:

std::vector<int> results;
std::copy_if(myvector.begin(), myvector.end(), std::back_inserter(results), IsOdd);

Now results contains the odd values. (Note the back:inserter is in the <iterator> header)

Solution 3

You can find the index of a vector iterator (and, more generally, any random-access iterator) by subtracting the start of the sequence:

std::cout << "The index is " << (it - myvector.begin()) << '\n';

Even more generally, there is a std::distance function which can give you the distance between forward iterators. You could use that, for example, if your container were a list; but you probably wouldn't want to, since it would be much slower.

To find all the odd numbers, you'll need a loop to call find again, starting from the element after the one you just found.

Solution 4

You'll need a loop. The iterator-algorithm design of the standard library makes this pretty easy:

#include <iterator>

for (auto it = myvector.begin();
     (it = std::find_if(it, myvector.end(), IsOdd)) != myvector.end(); )
{
    std::cout << *it << " at index " << std::distance(myvector.begin(), it) << "\n";
}

Solution 5

Change these two lines:

std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
std::cout << "The first odd value is " << *it << '\n';

into something like:

std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
while ( it != myvector.end() ) {
    std::cout << "The next odd value is " << *it << '\n';
    it = std::find_if (++it, myvector.end(), IsOdd);
}
Share:
11,075
Brett
Author by

Brett

Me, being me.

Updated on July 28, 2022

Comments

  • Brett
    Brett almost 2 years

    I'm learning C++, so I feel like this should be a very simple answer - but I can't seem to find it. So I apologize in advance if it's naive.

    I have a std::vector<int> of of values, and I am trying to find the indices of the odd values.

    I am following the code from here:

    (repeated below):

    // find_if example
    #include <iostream>     // std::cout
    #include <algorithm>    // std::find_if
    #include <vector>       // std::vector
    
    bool IsOdd (int i) {
      return ((i%2)==1);
    }
    
    int main () {
      std::vector<int> myvector;
    
      myvector.push_back(10);
      myvector.push_back(25);
      myvector.push_back(40);
      myvector.push_back(55);
    
      std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
      std::cout << "The first odd value is " << *it << '\n';
    
      return 0;
    }
    

    This example prints the first odd value. How could I extend this to give me the index values for each of the odd values in myvector? Is this the correct approach?

  • Lightness Races in Orbit
    Lightness Races in Orbit over 10 years
    Trolly challenge: can you make this work with a ranged-for? :)
  • Brett
    Brett over 10 years
    I needed the info about the distance (it - myvector.begin()). Thanks! Reading this in full really helps my understanding.
  • Kerrek SB
    Kerrek SB over 10 years
    @LightnessRacesinOrbit: "Can I", or "Would I reccommend it"? :-)
  • David Rodríguez - dribeas
    David Rodríguez - dribeas over 10 years
    nit: std::find_if(++it,...
  • wesley.mesquita
    wesley.mesquita over 10 years
    @DavidRodríguez-dribeas Sorry, but what is the advantage of ++ for this case? Is there any situation where the operator '+' is not overloaded? I did not get it. Thanks.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas over 10 years
    it+1 requires random access iterators, that is a stronger requirement than ++it (requires only forward iterators). In this particular case it is fine, as std::vector<>::iterator are random access, but using ++it makes the solution feasible for other containers.
  • Bill Door
    Bill Door over 10 years
    it - myvector.begin() is also known as distance(myvector.begin(), it). distance might help to better understand what is happening.
  • Bo R
    Bo R over 3 years
    You can simplify the loop with while(true). That way we don't check for end twice in every loop iteration.