Kaique S.
Kaique S.

Reputation: 45

Getting the max element in a vector of objects from a custom class

Consider the following blocks of code:

template<typename Prefs> class SocialPrefNode{

public:

// Constructors & Destructor
SocialPrefNode( );
SocialPrefNode( char self, std::vector<SocialPrefNode*> pref );
SocialPrefNode( const SocialPrefNode& copy );

~SocialPrefNode( );

// Setters
void set_id( char self );

void set_pref( std::vector<SocialPrefNode*> prefs );
void set_pref( SocialPrefNode& prefs );

void set_worse( std::vector<SocialPrefNode*> wrs );
void set_worse( SocialPrefNode& wrs );

void set_indiff( std::vector<SocialPrefNode*> indiff );
void set_indiff( SocialPrefNode& indiff );

// Getters
char get_id( ){ return id; }

std::vector<SocialPrefNode*> get_preferences( ){ return preferences; }
std::vector<SocialPrefNode*> get_worse( ){ return worsethan; }
std::vector<SocialPrefNode*> get_indiff( ){ return indifference; }

// Operators
SocialPrefNode& operator=( const SocialPrefNode& copy );

private:

char id{ };

std::vector<SocialPrefNode*> preferences{ };
std::vector<SocialPrefNode*> worsethan{ };
std::vector<SocialPrefNode*> indifference{ };
};

,and

std::vector<SocialPrefNode<char>> graph

, where the latter is made by pointing its elements to each other.

How can I get the maximum element, in terms of the size of the preferences vector's size, from graph?

I.e., I want to select elements from graph accordingly to preferences' size, in descending order.

I have considered using std::max_element( ), but it does not seem to apply to the aforementioned code, since I am using a vector of objects from a custom class where there are no properties to directly inform the compiler what is to be considered a greater or smaller element in the vector.

Thanks for the help.

Upvotes: 3

Views: 2926

Answers (2)

user1593858
user1593858

Reputation: 649

You can use std::max_element with a custom comparison function that compares the two objects however you'd like. See overload #3.

#include <vector>
#include <algorithm>
#include <cassert>

class Node
{
public:
    Node(const std::vector<int>& prefs) : prefs_(prefs) {}

    size_t numPrefs() const { return prefs_.size();}

    bool operator==(const Node& rhs) const { return prefs_ == rhs.prefs_;}

private:
    std::vector<int> prefs_;
};



int main(int argc, char** argv)
{
    Node one(std::vector<int>{1});
    Node two(std::vector<int>{1,2});
    Node three(std::vector<int>{1,2,3});

    std::vector<Node> nodes{one, two, three};

    auto comparison = [](const Node& a, const Node& b)
        {
            return a.numPrefs() < b.numPrefs();
        };

    auto max = std::max_element(nodes.begin(), nodes.end(), comparison);

    assert(*max == three);
    //assert(*max == two);  //Will fail
}

Upvotes: 4

Loki Astari
Loki Astari

Reputation: 264431

By default the standard library uses operator< to compare objects. So if your class SocialPrefNode<T> has either a function or member defined for operator< then it would work automatically.

//either:
template<typename T>
bool operator<(SocialPrefNode<T> const& lhs, SocialPrefNode<T> const& rhs);

// or
template<typename T>
class SocialPrefNode
{
    public:
    bool operator<(SocialPrefNod const& rhs) const;
};

If that is not viable then most standard library functions allow you to specify a comparator function as a last parameter. Looking at max_element this seems to be the case https://en.cppreference.com/w/cpp/algorithm/max_element

template< class ForwardIt, class Compare >
ForwardIt max_element( ForwardIt first, ForwardIt last, Compare comp );

The third parameter here is used to compare elements against each other. You can either pass a function, lamda, or object that can do the comparison.

auto m = std::max_element(std::begin(graph), std::end(graph),
                          [](auto const& lhs, auto const& rhs) -> bool
                          {
                              /* Do comparison */;
                          });

Upvotes: 4

Related Questions