Search code examples
c++stdset

how to search in a set in c++


I have a set of a class Item :

std::set <Item> items; 

class Item
{
   private:
      std::string name;
      std::string serialNum; 
      int count; 
      double unitPrice;
  public :
      Item(std::string _name, std::string _serialNum, int _count, double _unitPrice); 
      Item(); // Ctor with no parameters , for compiling 
      ~Item(); //Dtor 
      double totalPrice();
      bool operator<(Item const & other)const;
      bool operator>(Item& other);
      bool operator==(Item& other);
      void operator=(const Item& other);
      void countUp();
      void countDown();
      void setup(std::string _name, std::string _serialNum, int _count, double _UnitPrice); 
      int getCount() const ;
      std::string getName() const;
      std::string  getSerial() const ;
      double getPrice() const ;
      void printItem() const ;
 };

can I search in the set only by one value ? for instance, search in the set by item :: name .


Solution

  • std::set is ordered (in general using operator< which you can overload for your type). Usually, you decide for one specific order. (Maybe it is the serialNum in your case?)

    If you are searching the same set with a different criterion, e.g. name in your case, you need to traverse the whole set element by element, since there is no profit in the set order.

    For this, there is the standard algorithm std::find_if, which does this in linear time:

    std::string name_to_find = "foo bar";
    
    auto it = std::find_if(items.begin(), items.end(),
                 [name_to_find](const Item & i){ return i.getName() == name_to_find; });
    

    will give you an iterator it pointing to the first item in the set which has the name name_to_find (the end-iterator if no such element exists in the set). It is independent of the container type you supply, so it works with set, vector, arrays, ..., and ignores possible order of the container.


    The above code uses C++11 lambda to provide a compare function literally inline. If your compiler doesn't support that yet (or if you want to support older compilers), you have to use a functor to provide the same functionality. A functor is a class which acts like a function (can be called using operator()).

    // Functor class to compare the name of an item with a specific name to look for
    struct ItemByName {
        // The functor needs to remember what we're looking for in a member variable
        std::string name_to_find;
    
        // Constructor initializing the name to look for
        ItemByName(std::string name_to_find) : name_to_find(name_to_find) {}
    
        // The call-operator which is called by the algorithm find_if
        bool operator()(const Item &i) const {
            // This is the same body as in the lambda
            return i.getName() == name_to_find;
        }
    };
    

    and then use this in find_if by constructing an instance of this functor:

    std::set<Item>::iterator it = std::find_if(items.begin(), items.end(),
                 ItemByName(name_to_find));
    

    Note that the returned value is now captured in a variable with explicit type. In C++11 (above), we can use auto to make this easier to type.