how to find the max element of an std::vector using custom comparator

My problem:
I have a Directed Graph which contains Edges and Vertexes.
And I want to find the maximum length of the outgoing edges of a vertex.

Note: assume I already have the functions for:
1
2
Graph::get_outgoing_edges_of_a_vertex(vertex_t v);
Edge::GetLenght();


This can be trivially solved in 3 lines with:
1
2
3
int max_length = 0;
for (Edge * e: whGraph->get_outgoing_edges_of_a_vertex(v))
	max_length = std::max<int>(max_length, e->Length());


but can it also be solved using std::max_element (https://en.cppreference.com/w/cpp/algorithm/max_element )
by setting a custom <class Compare> with a Lambda Function
(I could not manage to implement it this way)

and is such a solution preferable to for loop shown above
Last edited on
I didn't put together an ad-hoc program to test it, but something like:
1
2
3
4
5
// max/sort/etc. functions require the equivalent of the < operator
bool edge_compare(const Edge* e1, const Edge* e2)
{
    return (e1->Length() < e2->Length());   
}

1
2
3
4
5
6
7
#include <iterator>
#include <algorithm>
// ...

    const auto& edges = whGraph->get_outgoing_edges_of_a_vertex(v);
    auto it = std::max_element(std::begin(edges), std::end(edges), edge_compare);
    std::cout << (*it)->Length() << '\n';


Edit: And using a lambda,
1
2
3
    auto it = std::max_element(std::begin(edges), std::end(edges),
        [](const Edge* e1, const Edge* e2) { return (e1->Length() < e2->Length()); } );
        

(remove the consts if Edge::Length is not const)

Edit: Contrived example to match your known interface
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Example program
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <limits>
#include <vector>

using vertex_t = int; // just for brevity

class Edge {
  public:
    Edge(int length)
    : length(length) { }
    
    int Length() const
    {
        return length;   
    }
    
  private:
    int length;
};

class Graph
{
  public:
    std::vector<Edge*> get_outgoing_edges_of_a_vertex(vertex_t v)
    {
        return std::vector<Edge*> {&e1, &e2, &e3, &e4};
    }
    
    Edge e1  {36};
    Edge e2  {42};
    Edge e3  {-3};
    Edge e4  {87};
    Edge e5 {128};
};

int main()
{
    Graph graph;
    Graph* whGraph = &graph;
    vertex_t v {};
    
    const auto& edges = whGraph->get_outgoing_edges_of_a_vertex(v);
    auto it = std::max_element(std::begin(edges), std::end(edges),
        [](const Edge* e1, const Edge* e2) { return (e1->Length() < e2->Length()); } );
        
    int max_length = (*it)->Length();
    std::cout << max_length << '\n';

}
Last edited on
1) super thanks this helps me understand lamda's a lot better
2)in c++ ref the function std::max_element<> has 2 generic arguments one of is <fowardIt> (which is self-explanatory)
and the second one is <class Compare> what is it for?
3)which of these 2 methods is preferable in terms of modern coding styles (from a performance perspective they are the same)
1
2
3
int max_length = 0;
for (Edge * e: whGraph->get_outgoing_edges_of_a_vertex(v))
	max_length = std::max<int>(max_length, e->Length());

1
2
const auto& edges = whGraph->get_outgoing_edges_of_a_vertex(v);
int max_length = (*std::max_element(std::begin(edges), std::end(edges), [](const Edge* e1, const Edge* e2) { return (e1->Length() < e2->Length()); } ))->Length();
2)in c++ ref the function std::max_element<> has 2 generic arguments one of is <fowardIt> (which is self-explanatory)


If you look at the cpp ref page in the possible implementation section it shows where the template parameter is used for the comparison function type.

3) , I would go with first simply because it's easier to read :+)
Ah didn't see this. Yes, I agree with TheIdeasMan. Template arguments by their nature are essentially "duck typing". So the Compare template argument is used like a 2-arg function that dereferences the two ForwardIt objects, so any function or function object that matches this and return something convertible into a bool will compile.

There are other requirements that the Compare object must adhere to, see https://en.cppreference.com/w/cpp/named_req/Compare for more details.

I also think the first excerpt is easier to read. While it is good to know what tools the standard library has available, sometimes it's easier to just keep it simple.
Topic archived. No new replies allowed.