I have a already-sorted vector called vec, and a target variable. The goal is to return the closest-to-target vector element.
I tried to use C++11 lambda function with [=] to capture outside variable
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec{1,2,3,4,5};
double target = 3.14159;
int res = min(vec.begin(), vec.end(), [=](int v1, int v2) -> bool {
return abs(v1-target) < abs(v2-target);
});
cout << res << endl;
return 0;
}
I expect to get res=3, but it returns an error:
error: cannot convert 'const __gnu_cxx::__normal_iterator<int*, std::vector<int> >' to 'int' in initialization
You are using the wrong algorithm. std::min
operates on two specific object passed as is, or on a std::initializer_list
. For containers, use std::min_element
instead. It returns an iterator, which needs to be dereferenced.
auto res = std::min_element(vec.cbegin(), vec.cend(), [=](int v1, int v2) -> bool {
return abs(v1-target) < abs(v2-target);
});
// Make sure that the range wasn't empty, i.e. res != vec.cend()...
const int min = *res;
Note that you might want to consider narrowing down the scope of your lambda closure by explicitly capturing the object that you need (in your case only one after all). And also consider passing .cbegin()
and .cend()
when you don't modify the container in question.
A solution that might potentially be more efficient and readable could use lower_bound
to find the greater of two elements that could potentially be returned.
int custom_bound(std::vector<int> const& vec, double target) {
if (vec.empty()) {
// throw or make the function return `optional`, choose to taste
}
auto lb = std::lower_bound(vec.begin(), vec.end(), target);
if (lb == vec.end()) {
return *(lb - 1);
} else if (lb == vec.begin()) {
return *lb;
} else {
const int up = *lb;
const int down = *(lb - 1);
return std::abs(up-target) < std::abs(down-target) ? up : down;
}
}
Unfortunately this can't be easily done as a one-liner. It doesn't require any custom functors, though; it merely exploits the fact that the number must lie in between (inclusive) lower_bound
and the iterator one before the LB.
We can make another observation that up
will be equal or greater to target
, while down
can only be smaller. Hence the condition could be replaced with
up-target < target-down
which removes the need for std::abs
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With