Thread: using the C++ sort stl

  1. #1
    Registered User
    Join Date
    Feb 2013
    Posts
    24

    using the C++ sort stl

    I'm tasked with building a program that sorts a list of employees by name and by salary using the sort stl in the c++ library. Theres a code at this site: STL Sort Comparison Function - CodeProject (see section "Function Pointer as a Comparison object")
    that I've been playing around with, (it sorts a person by age ive modified it to sort by name and age), but I would like to place the boolean functions inside of the Person class instead of outside it and make the age and name variables private. However, I get an error in my main file inside "std::sort", regarding my functions "sortName" and "sortAge" and with my private variables and I'm not sure how to fix it.

    sort header
    Code:
    class Person
    {
    public:
        // default constructor
        Person();
            
            //constructor for age and name empty
        Person(int a,string n) {
           
                age = a;
                   name = n;
           
                   
        };
            
            
     
         
    bool sortAge(Person a, Person b);
    
    
    bool sortName(Person a, Person b);
    
    
    
    
    private:
        int age;
        string name;

    sort.cpp
    Code:
    
    //sorts the age
    bool Person::sortAge(Person a, Person b)
    {
        
        return a.age < b.age;
    }
    //sorts the name
    bool Person::sortName(Person a, Person b){
       
        return a.name < b.name;
        
    }
    
           int main()
    {
        
     
        vector<Person> vecPerson;
           vecPerson.push_back(Person(22,"Calvin"));
          vecPerson.push_back(Person(20,"James"));
        vecPerson.push_back(Person(30,"Benny"));
        vecPerson.push_back(Person(28,"Alison"));
             vecPerson.push_back(Person(35,"Major"));
            vecPerson.push_back(Person(39,"Mark"));
         
                    //sorted by name
            cout << "******Sorted by Names*****\n";        
        std::sort(vecPerson.begin(), vecPerson.end(),sortName);
             
            for(size_t i=0; i<vecPerson.size(); ++i)
            std::cout<<vecPerson[i].name<<", "<<vecPerson[i].age<<std::endl;
    
                //sorts by number
         cout << "*****Names Sorted by Age*****\n";   
       std::sort(vecPerson.begin(),vecPerson.end(),sortAge);
    
        for(size_t i=0; i<vecPerson.size(); ++i)
            std::cout<<vecPerson[i].age<<", "<<vecPerson[i].name<<std::endl;
          
        
        return 0;
    }

  2. #2
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    Make those functions static.
    And pass ClassName::FunctionName as the argument.

    But, it is generally a good idea to keep the comparison functions globally accessible.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    For starters, "sortAge" and "sortName" should probably be renamed to "compareByAge" and "compareByName", respectively.

    There are a few approaches available here, e.g.,
    • Provide public member functions to get the age and the name, then implement non-member comparison functions using these public member functions.
    • Declare the comparison functions as friends of the Person class.
    • Declare the comparison functions as members of the Person class, then have wrapper non-member functions call these comparison members functions.


    A few other things to note:
    • You should indent your code more consistently.
    • You should fully qualify the names in the parameter list and member variable declaration, i.e., use std::string instead of string, since a class definition like this most likely goes into a header file where a using directive or using declaration at file scope is a Bad Thing.
    • You should make use of the constructor's initialiser list instead of assigning member variables in the constructor body to give them an initial value.
    • You should pass std::string and Person objects by (const) reference unless you really do intend to copy them.
    Last edited by laserlight; 04-22-2013 at 05:46 AM.
    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

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    You can add class functions to get the age or name if you want them private, and the functions need to return an integer since the return values are -1, 0, +1.

    Code:
    int Person::compareAge(Person a, Person b) {
        return a.getage() < b.getage(); 
    } 
    
    int Person::compareName(Person a, Person b){ 
        return a.getname() < b.getname(); 
    } 
    


    Also if you plan to do the sorting first by age, then by name to end up sorted by name and age, you'll need to use stable_sort() instead of sort(), since sort() will rearrange the order of equal elements, while stable_sort() will retain the original order of equal elements.



    Last edited by rcgldr; 04-22-2013 at 08:50 AM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by rcgldr
    You can add class functions to get the age or name if you want them private, and the functions need to return an integer since the return values are -1, 0, +1.
    No, std::sort (and std::stable_sort) make use of comparators that return bool (as in true for a "less than" comparison), rather than an integer akin to the interface qsort requires. Furthermore, if you are going "to get the age or name if you want them private", then the comparators themselves can be non-member non-friend functions.
    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

  6. #6
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by laserlight View Post
    No, std::sort (and std::stable_sort) make use of comparators that return bool (as in true for a "less than" comparison)
    Sorry, brain fade on my part. You're correct about the bool return value, and also the compare part, it should be:

    Code:
    bool Person::compareAge(Person a, Person b) {
       return a.getage() < b.getage(); 
    } 
    
    bool Person::compareName(Person a, Person b){ 
       return a.getname() < b.getname(); 
    } 
    
    or as mentioned by laserlight, there's no need to make these class member functions:

    Code:
    bool compareAge(Person a, Person b) {
       return a.getage() < b.getage(); 
    } 
    
    bool compareName(Person a, Person b){ 
       return a.getname() < b.getname(); 
    }
    

    Last edited by rcgldr; 04-22-2013 at 11:05 AM.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by rcgldr
    but the comparson needs to be less than or equal in order for stable_sort to preserve the order of equal elements:
    No, the comparison must be strictly "less than". The standard mandates that and it is up to the implementation to work with it, e.g., use the fact that mathematically (a <= b) == !(b < a).
    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

  8. #8
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    update you need <= is incorrect, you need <. Previous and later posts corrected based on feedback from laserlight.
    Last edited by rcgldr; 04-22-2013 at 11:17 AM.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by rcgldr
    From the help info for stable_sort(): "User-defined predicate function object that defines the comparison criterion to be satisfied by successive elements in the ordering. A binary predicate takes two arguments and returns true when satisfied and false when not satisfied."
    That is certainly correct. Unfortunately, it does not say how you should go about defining the predicate, so it does not support your point.

    Quote Originally Posted by rcgldr
    For stable_sort() to be stable and produce an ascending order, you need <=.
    Refer to:
    Quote Originally Posted by C++11 Clause 25.4 Paragraphs 3 and 4
    For all algorithms that take Compare, there is a version that uses operator< instead. That is, comp(*i, *j) != false defaults to *i < *j != false. For algorithms other than those described in 25.4.3 to work correctly, comp has to induce a strict weak ordering on the values.

    The term strict refers to the requirement of an irreflexive relation (!comp(x, x) for all x), and the term weak to requirements that are not as strong as those for a total ordering, but stronger than those for a partial ordering. If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp
    and equiv both be transitive relations:
    • comp(a, b) && comp(b, c) implies comp(a, c)
    • equiv(a, b) && equiv(b, c) implies equiv(a, c) [ Note: Under these conditions, it can be shown that
      • equiv is an equivalence relation
      • comp induces a well-defined relation on the equivalence classes determined by equiv
      • The induced relation is a strict total ordering.

      —end note ]
    Note that std::stable_sort is described in clause 25.4.1.2. Notice that <= is reflexive and hence does not satisfy the requirements. Failure to satisfy these requirements leads to undefined behaviour.

    Quote Originally Posted by rcgldr
    If the goal is descending order, you need >.
    Notice that > induces a strict weak ordering, so there is no problem with this.
    Last edited by laserlight; 04-22-2013 at 10:49 AM.
    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

  10. #10
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by laserlight View Post
    strict weak ordering.
    You're correct on this. Looking at the code in algorithm, it's using less than to check for out of order by checking for a < b, where a is currently after b in a list of elements. I corrected my previous post, and resposting what the functions should look like here:

    Code:
    bool Person::compareAge(Person a, Person b) {
        return a.getage() < b.getage(); 
    } 
    bool Person::compareName(Person a, Person b){ 
        return a.getname() < b.getname(); 
    }
    or as mentioned by laserlight, there's no need to make these class member functions:
    Code:
    bool compareAge(Person a, Person b) {
        return a.getage() < b.getage(); 
    } 
    bool compareName(Person a, Person b){ 
        return a.getname() < b.getname(); 
    }

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by rcgldr
    You're correct on this. Looking at the code in algorithm, it's using less than to check for out of order by checking for a < b, where a is currently after b in a list of elements.
    Well, if the code that you saw disagrees with me, then it is the code that is incorrect, not me, since the standard agrees with me

    Quote Originally Posted by rcgldr
    there's no need to make these class member functions:
    and there is no need to pass by value:
    Code:
    bool compareAge(const Person& a, const Person& b) {
        return a.getage() < b.getage();
    }
    
    bool compareName(const Person& a, const Person& b) {
        return a.getname() < b.getname();
    }
    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

  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    regarding my functions "sortName" and "sortAge" and with my private variables and I'm not sure how to fix it.
    O_o

    What is wrong with just declaring them `friend'?

    Soma

  13. #13
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by rcgldr View Post
    You're correct on this. Looking at the code in algorithm, it's using less than to check for out of order by checking for a < b, where a is currently after b in a list of elements.
    Quote Originally Posted by laserlight View Post
    Well, if the code that you saw disagrees with me, then it is the code that is incorrect, not me, since the standard agrees with me.
    The code agrees with you. The sorts are using the less than operator for compares, but orders the parameters to the compare function so that TRUE from the compare function means out of order: if(later_element < earlier_element) then elements are out of order. I never noticed this before. Thanks for the information on this (I just updated 6 example sort programs I have to comply with the STL standard for the compare).

    Quote Originally Posted by laserlight View Post
    and there is no need to pass by value.
    laserlight is correct, there's no point in copying entire classes onto the stack when the goal is to just compare a pair of class members.
    Last edited by rcgldr; 04-22-2013 at 12:29 PM.

  14. #14
    Registered User
    Join Date
    Feb 2013
    Posts
    24
    Quote Originally Posted by rcgldr View Post
    You're correct on this. Looking at the code in algorithm, it's using less than to check for out of order by checking for a < b, where a is currently after b in a list of elements. I corrected my previous post, and resposting what the functions should look like here:

    Code:
    bool Person::compareAge(Person a, Person b) {
        return a.getage() < b.getage(); 
    } 
    bool Person::compareName(Person a, Person b){ 
        return a.getname() < b.getname(); 
    }
    or as mentioned by laserlight, there's no need to make these class member functions:
    Code:
    bool compareAge(Person a, Person b) {
        return a.getage() < b.getage(); 
    } 
    bool compareName(Person a, Person b){ 
        return a.getname() < b.getname(); 
    }
    The only reason why I wanted to have the boolean functions as class member functions was because I have to use a header file which contains them inside of a class. (We are using cxxtesting to test our code online and we need to include certain functions in our header file otherwise it won't pass our professor's test)

  15. #15
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    The only reason why I wanted to have the boolean functions as class member functions was because I have to use a header file which contains them inside of a class.
    No. You don't.

    Your original code already exhibits a separation of header (declarations) and source (implementations), and as well separates the functions from the class as non-member functions.

    *shrug*

    Well, I guess your original code may also fail to match this requirement, but it is much more likely that you are simply imaging a non-existent requirement holding to the notion because you got errors related to access rights. (The inaccessibility of `private' members.)

    We are using cxxtesting to test our code online and we need to include certain functions in our header file otherwise it won't pass our professor's test.
    I'm unfamiliar with the framework, but the implementation for your constructor from your example is already not included in the header; you have only provided a declaration.

    Assuming that such is an actual requirement, your only legitimate alternative is `inline' implementations, but before you go that path, you'll probably lose points for going that path.

    Soma

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 26
    Last Post: 07-05-2010, 10:43 AM
  2. Replies: 1
    Last Post: 01-26-2010, 09:02 AM
  3. Replies: 4
    Last Post: 12-06-2009, 12:27 PM
  4. merge sort and selection sort and time spent on both
    By misswaleleia in forum C Programming
    Replies: 3
    Last Post: 06-04-2003, 02:24 PM
  5. Shell Sort vs Heap Sort vs Quick Sort
    By mackol in forum C Programming
    Replies: 6
    Last Post: 11-22-2002, 08:05 PM