Here is the task came to me from a code review. I want to select a minimum value from a set, based on a special kind of compare predicate. Like this:
struct Complex { ... };
float calcReduction(Complex elem);
Complex findMinValueWithPredicates(const std::vector<Complex>& values)
{
auto it = std::min_element(values.begin(), values.end(),
[](const Complex& a, const Complex& b) {
return calcReduction(a) < calcReduction(b);
});
if (it == values.end()) throw std::runtime_error("");
return *it;
}
Here I find the minimum element based on a predicate. This predicate computes a reduction of both values to float
and then compares those floats. Works fine, looks neat.
Can you see the problem? Yes, for a set of N
elements calcReduction()
is called 2N
times, while it is enough to compute it only N
times - once for each element.
One way to solve this problem is to write explicit computations:
Complex findMinValueExplicit(const std::vector<Complex>& values)
{
float minReduction = std::numeric_limits<float>::max();
Complex minValue;
for (Complex value : values)
{
float reduction = calcReduction(value);
if (reduction < minReduction)
{
minReduction = reduction;
minValue = value;
}
}
if (minReduction == std::numeric_limits<float>::max()) throw std::runtime_error("");
return minValue;
}
It works fine and we only have N
calls to calcReduction()
. However, it looks too verbose and the intent is not such clear, as compared to explicit call of min_element
. Because when you call min_element
it is really easy to guess you are going to find a minimum element, you know.
The only idea I have for now is to create my own algorithm like min_element_with_reduction
, accepting a range and a reduction function. Sounds reasonable, but I wonder whether there are any ready solutions.
Any ideas on how to solve this task with clear intent and some ready solutions? Boost is welcomed. C++17 and ranges are interesting to see.