9

std::min_element will return the smallest element as defined either by operator<(T,T) or by a custom predicate bool Pred(T,T). Is there a similar function which returns the element for which the projection function f(T)->R takes on the minimal value?

Obviously I can define bool Pred(t1,t2) { return f(t1) < f(t2); } but that's a bit inconvenient when f is a lambda.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 2
    Calculate the derivative of `f`. *Ok ok I know that was a bad joke* – Bartek Banachewicz Jul 18 '13 at 10:04
  • But when banks used derivatives, it caused a financial crisis _Even worse joke_ :P – MSalters Jul 18 '13 at 10:12
  • 1
    If `f` is a lambda, you can pass it to a C++1y higher-order polymorphic lambda `[]( auto f ) { return [](auto t1, auto t2){ return f(t1) < f(t2); }; }` (Think I got the parens balanced.) Of course that's twice as much computation as you need. – Potatoswatter Jul 18 '13 at 10:12
  • are you looking for a way of not having to write your *projection* `R(T)` more than once and not having it clutter up the outer scope? – Filip Roséen - refp Jul 18 '13 at 10:16
  • @refp: That's the gist of the question. – MSalters Jul 18 '13 at 10:59
  • No, there isn't, because everything can be described using a custom comparator (even if inconvenient), which would make an additional overload redundant, as well as the corresponding overload for custom projection with custom comparator, or custom projected projection with custom transforming comparator, or... – Christian Rau Jul 18 '13 at 12:30
  • @Potatoswatter: You do realize what the actual use would be? `std::min_element(begin(X), end(X), []( auto f ) { return [](auto t1, auto t2){ return f(t1) < f(t2); }; }([&](T1 t)->R { return t.foo()/t.bar(); }));` - looks suspiciously like Perl. – MSalters Jul 18 '13 at 22:35
  • @MSalters No, the higher-order function can be kept in a header. (The suggestion was somewhat in jest, but the actual answers ended up quite similar.) – Potatoswatter Jul 18 '13 at 22:44

2 Answers2

5

Why not use a boost::transform_iterator (which used to be called projection_iterator_adaptor) from the Boost.Iterator library

auto Pred = [](some_value_type const& x){ /* your lambda here */ };
auto result = std::min_element(
    boost::make_transform_iterator(begin(container), Pred),    
    boost::make_transform_iterator(end(container), Pred)
).base(); 
//^^^^^^^  <-- to get back an iterator to the original sequence

The advantage of this over writing a special less predicate are that you can reuse this approach for all other algorithms (e.g. for std::max_element you would need a special greater predicate etc.).

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
4

Why not just define a predicate generator less_by which, taking a lambda, returns a functor that does the job for you?

template <typename Proj>
struct less_by_t {
    Proj p;

    template <typename T>
    bool operator ()(T const& a, T const& b) const {
        return p(a) < p(b);
    }
};

template <typename Proj>
less_by_t<Proj> less_by(Proj p) {
    return {p};
}
auto result = std::min_element(begin, end, less_by([](T const& x){return …;}));
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214