7

(This is a related question, but there are difference with my case that makes me doubt my understanding of it).

I have this class:

class MyOwnClass
{ 
public:
    int score; Specialcustomtype val1; double index;
private:

};

and a vector of MyOwnClass

vector<MyOwnClass> MySuperVector(20);

Having some code that set values to the fields of MyOwnClass, I want to find which MyOwnClass in the vector has the field score with the highest value.

In an answer from the related questions :

#include <algorithm> // For std::minmax_element
#include <tuple> // For std::tie
#include <vector> // For std::vector
#include <iterator> // For global begin() and end()

struct Size {
    int width, height;
};

std::vector<Size> sizes = { {4, 1}, {2, 3}, {1, 2} };

decltype(sizes)::iterator minEl, maxEl;
std::tie(minEl, maxEl) = std::minmax_element(begin(sizes), end(sizes),
    [] (Size const& s1, Size const& s2)
    {
        return s1.width < s2.width;
    });

But in my case, the fields of MyOwnClass are of different types and my attempts at using "max_elements" have failed.

Of course I could loop among the n elements of the vector and use a comparison to find which object has the highest score, and it works but I am sure that the built-in functions of c++ are more efficient thant my version.

Community
  • 1
  • 1
Doombot
  • 553
  • 3
  • 8
  • 18
  • What do you mean by `fields of MyOwnClass are of different types`? – NaCl Nov 05 '14 at 20:11
  • I mean that score is an int, val1 is of type Specialcustomtype (an invented one) and index is a double. I only want to take into account the score field – Doombot Nov 05 '14 at 20:12
  • 1
    So why don't you overload `operator<()` and check `score` only? – David G Nov 05 '14 at 20:14
  • 1
    @Doombot - I don't quite get why you couldn't take the example you posted and just tailored it to find the lowest score. It's practically a copy/paste solution. Just replace the vector with your vector, and the field being compared with the field you want to compare. – PaulMcKenzie Nov 05 '14 at 20:18
  • Yes that's what I did, but somehow the ::iterator keyword is making trouble. @Vlad from Moscow's version works, on the other hand. – Doombot Nov 05 '14 at 20:26

3 Answers3

18

Try the following

std::vector<MyOwnClass> MySuperVector(20);

//..filling the vector

auto max = std::max_element( MySuperVector.begin(), MySuperVector.end(),
                             []( const MyOwnClass &a, const MyOwnClass &b )
                             {
                                 return a.score < b.score;
                             } ); 

If you need to find the minimum and maximum element simultaneously then you can use standard algorithm std::minmax_element. It returns a pair of iterators the first of which points to the first minimum element and the second points to the last maximum element. Otherwise you need to call std::max_element and std::min_element separatly. if you need to get the first minimum and the first maximum or the last minimum and the last maximum

The other approach is to define internal functional objects for each field that can be used for finding maximum or minimum. For example

class MyOwnClass
{ 
public:
    int score; Specialcustomtype val1; double index;

    struct ByScore
    {
        bool operator ()( const MyOwnClass &a, const MyOwnClass &b ) const
        { 
            return a.score < b.score;
        }
    };

    struct ByIndex
    {
        bool operator ()( const MyOwnClass &a, const MyOwnClass &b ) const
        { 
            return a.index < b.index;
        }
    };
private:

};

//...

auto max_score = std::max_element( MySuperVector.begin(), MySuperVector.end(),
                                   MyOwnClass::ByScore() ); 

auto max_index = std::max_element( MySuperVector.begin(), MySuperVector.end(),
                                   MyOwnClass::ByIndex() ); 
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Note that if `score` were an expensive computation function rather than a simple public member variable, you'd be better off doing your own looping to minimize the number of times it was called. Otherwise, for example, `MySuperVector[0].score()` could be called multiple times (compare element 0 to element 1, now compare element 0 to element 2). – dlf Nov 05 '14 at 20:19
  • I haven't asked originally but let's say there are no "index" field and I want to know which object in the vector that possess the maximum score field, how would you do that? I am currently trying to use std::distance – Doombot Nov 05 '14 at 20:53
  • Ok I used: int hihihihi = distance(MySupervector.begin(), max); cout << "Index = " << hihihihi << endl; and it works. Tanks Vlad! :) – Doombot Nov 05 '14 at 21:07
5

That your elements are of different types it doesn't matter, you can always compare the field you're interested in:

std::vector<MyOwnClass> MySuperVector(20);

// A pred function to adjust according to your score
bool comparator(const MyOwnClass& s1, const MyOwnClass& s2) {
    return s1.score < s2.score;
}

int main() {
    MySuperVector[0].score = 23; // This will be returned
    MySuperVector[1].score = 2;
    MySuperVector[5].score = -22;

    auto element = std::max_element(MySuperVector.begin(), 
                                    MySuperVector.end(), comparator);

    std::cout << element->score; // 23
}

Example

Notice that you don't even need the minmax_element function since you're just asking for the greatest element (max_element is a better fit).

If the runtime efficiency to find your greatest value matters, you might want to take a look at priority_queues (heap adaptors).

Marco A.
  • 43,032
  • 26
  • 132
  • 246
-2
class test
{
private:
int num;
public:
test()
{
    num = 0;

}
test(int n)
{
    num = n;
}
void get(test ob1,test ob2)
{
    if (ob1.num > ob2.num)
    {
        cout << "Max Object nu is:" << ob1.num << endl;
    }
    else
    {
        cout << "Max Object number is:" << ob2.num << endl;
    }
}

};
void main()
{
test a(6);
test b(4);
test c;
c.get(a,b);
system("pause");
}