C++ lambda 函数 - 如何返回与目标相比最接近的矢量元素

C++ lambda function - how to return closest vector element compared to target

本文关键字:目标 最接近 元素 函数 lambda 何返回 返回 C++      更新时间:2023-10-16

我有一个已经排序的向量,叫做vec,还有一个目标变量。目标是返回最接近目标的矢量元素。

我尝试将 C++11 lambda 函数与 [=] 一起使用来捕获外部变量

#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;
}

我希望得到 res=3,但它返回一个错误:

error: cannot convert 'const __gnu_cxx::__normal_iterator<int*, std::vector<int> >' to 'int' in initialization

您使用了错误的算法。 std::min对按原样传递的两个特定对象或std::initializer_list进行操作。对于容器,请改用std::min_element。它返回一个迭代器,需要取消引用。

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;

请注意,您可能需要考虑通过显式捕获所需的对象(在您的情况下只有一个对象(来缩小 lambda 闭包的范围。并且还可以考虑在不修改相关容器时传递.cbegin().cend()

可能

更有效和可读的解决方案可以使用lower_bound来查找可能返回的两个元素中的较大者。

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;
    }
}

不幸的是,这不能轻易地作为单行完成。不过,它不需要任何自定义函子;它只是利用了这样一个事实,即数字必须位于(包含(lower_bound和迭代器之间,在 LB 之前。

我们可以再观察一下,up等于或大于target,而down只能更小。因此,条件可以替换为

up-target < target-down

这消除了对std::abs的需要。