Thread: applying the std::find function to a vector of structures vector<myStruct) vec

  1. #1
    Registered User FortranLevelC++'s Avatar
    Join Date
    May 2013
    Location
    United States
    Posts
    81

    applying the std::find function to a vector of structures vector<myStruct) vec

    I have asked a related question before, and it was resolved successfully. In the past, when I wanted to use std::max_element in order to find the maximum element (or even sort by using std::sort) of a vector of structures according to one of the members of the structure, all I had to do was to insert a specially designed comparison function as the third argument of the function std::max::element. But the latter comparison function naturally accepts two arguments internally.

    For instance, here is a test program that successfully finds the maximum according to just one member of the structure:

    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    
    
    using namespace std;
    struct S {
      string myWord;
      int a;
      int b;
    };
    
    
    
    int main()
    { 
       vector<S> vec;
    
    
       for(int j=0; j<10; j++) { //Initialize:
             S tempS;
         tempS.a = j;
         tempS.b = 5+j;
         tempS.myWord = "aWord";
         vec.push_back(tempS);
       }
        
      
       std::vector<S>::iterator result;
         result = std::max_element(vec.begin(), vec.end(), [](const S & S_0, const S & S_1)  { return ( S_0.a < S_1.a ) ; } ) ;
       
    
       cout << "Maximum element S.a of vector<S> vec is at: " << std::distance(vec.begin(), result) << endl;
       cout << "---------------------------------------------" << endl;
    
    
       size_t range = 3 ;
       size_t index_max;
       
       for(vector<S>::iterator itr=vec.begin( ) + 6  ;  itr != vec.end( )  ;  itr++)
       {  
          size_t index = itr - vec.begin();
          vector<S>::iterator first = itr -range;
          //std::max_element(first, last) returns an answer between [first,last) as half-open interval
          //and so we need to further increase last=itr+1 as follows 
          // (or else the last element does not get compared):
          vector<S>::iterator last = itr +  1 ;
         // result = std::max_element( first , last, CompForMax_a  );
          result = std::max_element( first , last,  [](const S & S_0, const S & S_1)  { return ( S_0.a < S_1.a ) ; }   );
          index_max = std::distance(vec.begin(), result);
          cout << "max element of vec[i].a between slot " << index -range  << " and slot "
             << index << " is: " <<  (*result).a << ", and its index is: " <<  index_max << endl;
          cout << "vec[" << index << "].a = " << (*itr).a << endl;
          
       }
    
    }
    And the output was this, as expected:

    Maximum element S.a of vector<S> vec is at: 9
    ---------------------------------------------
    [I]max element of vec.a between slot 3 and slot 6 is: 6, and its index is: 6
    vec[6].a = 6
    [I]max element of vec.a between slot 4 and slot 7 is: 7, and its index is: 7
    vec[7].a = 7
    [I]max element of vec.a between slot 5 and slot 8 is: 8, and its index is: 8
    vec[8].a = 8
    [I]max element of vec.a between slot 6 and slot 9 is: 9, and its index is: 9
    vec[9].a = 9




    -------------------------------------------------------

    However, I now need to search and find an element of vector<myStruct> according to just one member of myStruct, instead of finding the maximum or sorting as before. This presents a problem because the function std::find does not accept such a comparison function as its third argument.

    This was the description of the std::find function that I found:
    find - C++ Reference
    Code:
     
    
    template <class InputIterator, class T>   InputIterator find (InputIterator first, InputIterator last, const T& val);
    
    
    I could also find another function called std::find_if, but this only accepts a unary predicate like this:
    find_if - C++ Reference
    Code:
     
    
    template <class InputIterator, class UnaryPredicate>   InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred);
    And once again this is either inadequate of I don't see how to use it directly, because for the third argument I would like to insert a function that takes two arguments with a syntax like this:
    Code:
    int x=7;
    
    std::vector<S>::iterator result;
       result = std::find(vec.begin(), vec.end(), []( const (int x, const S & S_1)  { return (  x == S_1.a ) ; } ) ;

    Is there another std function that I can use to make search and find an element according to just one member of myStruct?

    Or perhaps there is a clever way to pass two arguments to the unary predicate.
    Many thanks.




    Last edited by FortranLevelC++; 07-05-2013 at 02:01 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    std::find_if is appropriate here. One solution is to create a function object with the value that you want to compare against as a member variable. Another option, more in line with what you already have, is to make use of the x variable by bringing it into the scope of the lambda function, e.g.,
    Code:
    std::vector<S>::iterator result = std::find_if(
        vec.begin(),
        vec.end(),
        [x](const S& s) { return s.a == x; }
    );
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User FortranLevelC++'s Avatar
    Join Date
    May 2013
    Location
    United States
    Posts
    81
    Quote Originally Posted by laserlight View Post
    std::find_if is appropriate here. One solution is to create a function object with the value that you want to compare against as a member variable. Another option, more in line with what you already have, is to make use of the x variable by bringing it into the scope of the lambda function, e.g.,
    Code:
    std::vector<S>::iterator result = std::find_if(
        vec.begin(),
        vec.end(),
        [x](const S& s) { return s.a == x; }
    );

    This is the perfect solution, and I can see that I will be using this syntax for many years in the future! The trouble is that I don't yet understand the lambda functions. I need to do more homework from C++ books.

    Many thanks LaserLight: you have answered my question with the speed of light.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    You're welcome. I notice that this site has a guide to Lambda Functions in C++11 which may be more accurate than the description that I have used.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User FortranLevelC++'s Avatar
    Join Date
    May 2013
    Location
    United States
    Posts
    81
    Quote Originally Posted by laserlight View Post
    You're welcome. I notice that this site has a guide to Lambda Functions in C++11 which may be more accurate than the description that I have used.

    Yes, I have been looking at Alex Allain's tutorial for several weeks, but the subject matter is difficult to internalize and understand without doing some homework, which is what I need.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 06-13-2013, 06:15 PM
  2. How to find Index positions with a vector STL?
    By codeguy in forum C++ Programming
    Replies: 6
    Last Post: 01-11-2008, 01:07 PM
  3. How to find index of a particular record in a vector?
    By ketu1 in forum C++ Programming
    Replies: 7
    Last Post: 01-02-2008, 12:22 PM
  4. Vector of Structures
    By loopshot in forum C++ Programming
    Replies: 3
    Last Post: 10-23-2005, 09:19 PM
  5. Vector of structures
    By Highland Laddie in forum C++ Programming
    Replies: 6
    Last Post: 09-13-2005, 09:22 PM