dcsimg
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5

Thread: search vector of objects for object with specific attribute value

  1. #1
    Join Date
    May 2009
    Location
    Boston
    Posts
    360

    search vector of objects for object with specific attribute value

    Hello,

    I run into this often enough that I would like to lock down a good method.

    If I have a simple class and a container,
    Code:
    class important_vertex {
    public:
       // initialize class members
       important_vertex()
          : vertex_number(0),
            some_other_value(0) { }
    
       unsigned int vertex_number, some_other_value;
       vector<unsigned int> some_list;
    };
    
    vector<important_vertex> important_vertex_list;
    If I want to find the object in important_vertex_list with a specific value for vertex_number, how would I go about that? We can assume that there will be no two objects with the same value for vertex_number, though it would be nice to see how to trap that.

    I know how to find an object in a map setting an iterator to the return value of find(), but this assumes that you have registered the object with the key value you intend to use as a lookup. This is a different scenario since I could be looking for any object attribute. I assume I would set an iterator to the return value of find_if() but I'm not sure what that would look like. Do I need a functor to direct the find_if()?

    LMHmedchem

  2. #2
    Join Date
    May 2009
    Location
    Boston
    Posts
    360

    Re: search vector of objects for object with specific attribute value

    Well I have something working with the following,
    Code:
    class important_vertex {
    public:
       // initialize class members
       important_vertex()
          : vertex_number(0),
            some_other_value(0) { }
    
       unsigned int vertex_number, some_other_value;
       vector<unsigned int> some_list;
    };
    
    // custom search operator
    struct object_has_vertex_number {
       object_has_vertex_number(unsigned int const& search_value) : vertex_to_find(search_value) { }  
       bool operator () (important_vertex const& current_object) {
          return current_object.important_vertex == vertex_to_find;
       }
    private:
       unsigned int vertex_to_find;
    };
    
    // vector of objects and iterator
    vector<important_vertex> important_vertex_list;
    vector<important_vertex>::iterator obj_location;
    
    // some important_vertex.vertex_number I am looking for
    unsigned int search_value = 3;
    
    // find position for acceptor atom in acceptor object list
    obj_location = find_if( important_vertex_list.begin(),
                            important_vertex_list.end(),
                            object_has_vertex_number(search_value) );
    
    // access object attributes with
    (*obj_location).vertex_number
    (*obj_location).some_other_value
    
    // or
    obj_location->vertex_number
    obj_location->some_other_value
    ...
    I copied and modified this from an example where the search type was a string and not an int. This code does seem to allow me to set search_value and search a vector of objects to find the object where obj.vertex_number == search_value. I don't really understand the syntax well enough to fully understand why this works or how to write similar code without an example to copy from. If someone could translate struct object_has_vertex_number {} from above, that would be very helpful.

    If there is a better, or more standard, way to do this, I would appreciate some information on that.

    LMHmedchem

  3. #3
    Join Date
    Jun 2015
    Posts
    208

    Re: search vector of objects for object with specific attribute value

    Quote Originally Posted by LMHmedchem View Post
    If there is a better, or more standard, way to do this, I would appreciate some information on that.
    If you just want to visit the items of a data structure sequentially I'd say the most standard and straightforward way (as of C++ 11) would be to use the range-based for-loop,

    Code:
    for (const auto& current_object : important_vertex_list) { // vist all items
        if (current_object.important_vertex == vertex_to_find) {
                       // item found!
                       // possibly do something 
            break; // before exiting the loop
        }
    }
    With const auto& the item type is automatically deducted, the item is constant and cannot (accidentally) be modified, and the item is never actually read (but held by reference &) to avoid (potentially) expensive copying. The only requirement on the data structure is that it supports sequential iteration (and std::vector certainly does).

    The next step up would be to scan the data structure by way of some function supplied with some criterion in the form of a lambda expression (again as of C++ 11). It has advantages but it might as well just be a complication.
    Last edited by tiliavirga; October 4th, 2015 at 04:48 AM.

  4. #4
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    6,972

    Re: search vector of objects for object with specific attribute value

    If someone could translate struct object_has_vertex_number {} from above, that would be very helpful.
    The third parameter for find_if() is a unary function that accepts an element in the range as argument and returns a value convertible to bool. The value returned indicates whether the element is considered a match in the context of this function. See http://www.cplusplus.com/reference/algorithm/find_if/

    When a class is used for the unary function, simplistically two things happen
    1) The class constructor is called once with its parameter the specified argument (searchvalue in this case). The class constructor usually stores this value in a private member variable (vertex-to_find in this case).

    2) For every value in the first..last range (excluding last - usually .begin() to .end()) the class operator () is called with the value as its parameter (current_object in this case). This () function returns a bool which should be true if the condition required is met or false otherwise.

    When find_if() sees that the function has returned true for a specific value in the range, it stops and returns this value. If it reaches the end of the range then it returns the value of last (usually .end()). So the value returned by find_if() should be tested for .end() (or the last value) before use in case no matches were found.

    NB. There is a problem with this code
    Code:
    bool operator () (important_vertex const& current_object) {
          return current_object.important_vertex == vertex_to_find;
       }
    important_vertex is a type, not a class member. Should this be
    Code:
    bool operator () (important_vertex const& current_object) {
          return current_object.vertex_number == vertex_to_find;
       }
    Last edited by 2kaud; October 4th, 2015 at 01:35 PM. Reason: NB
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++17 Compiler: Microsoft VS2019 (16.4.2)

  5. #5
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    6,972

    Re: search vector of objects for object with specific attribute value

    If you are using c++11, you could also use a lamda expression with the find_if() rather than using a functor.

    Code:
    class important_vertex {
    public:
       // initialize class members
       important_vertex()
          : vertex_number(0),
            some_other_value(0) { }
    
       unsigned int vertex_number, some_other_value;
       vector<unsigned int> some_list;
    };
    
    vector<important_vertex> important_vertex_list;
    
    // some important_vertex.vertex_number I am looking for
    unsigned int search_value = 3;
    
    auto obj_location = find_if(important_vertex_list.begin(), important_vertex_list.end(),
    		[&](const auto& vert) {return vert.vertex_number == search_value;});
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++17 Compiler: Microsoft VS2019 (16.4.2)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)