c++ - 需要 C++ 中非常通用的 argmax 函数

标签 c++ templates generics functional-programming

我是一个被宠坏的 Python 程序员,习惯于计算 argmax collection 的一些 function with

max(collection, key=function)

例如:

l = [1,43,10,17]
a = max(l, key=lambda x: -1 * abs(42 - x))

a 然后包含 43,这是最接近 42 的数字。

是否可以编写一个 C++ 函数,它接受任何“可迭代”和任何函数并像上面那样返回 argmax?我想这会涉及模板参数、auto 关键字和 range-based iteration , 但我无法将其拼凑起来。

最佳答案

这是一个两步过程。定义一个函数 key应该将其映射到元素,即在查找最大值的操作之前应用它。在 lambda 表达式中将事物组合在一起定义比较以找到最大值。

auto key = [](int x){
    return -abs(42 - x);
};

std::max_element(l.begin(), l.end(), [key](int a, int b){
    return key(a) < key(b);
});

在这里,我们必须捕获key这是在第二个 lambda 函数之外定义的。 (我们也可以在里面定义它)。您也可以将它放在一个单独的 lambda 函数中。当应从 lambda 外部参数化 42 时,将其捕获为变量:

int x = 42;
std::max_element(l.begin(), l.end(), [x](int a, int b){
    return -abs(x - a) < -abs(x - b);
});

请注意 std::max_element返回一个迭代器。要访问值/对它的引用,请在其前面加上 * :

int x = 42;
auto nearest = std::min_element(l.begin(), l.end(), [x](int a, int b){
    return abs(x - a) < abs(x - b);
});
std::cout << "Nearest to " << x << ": " << *nearest << std::endl;

您可以将它很好地包装在一个通用的 find_nearest 中功能:

template<typename Iter>
Iter find_nearest(Iter begin, Iter end,
                  const typename std::iterator_traits<Iter>::value_type & value)
{
    typedef typename std::iterator_traits<Iter>::value_type T;
    return std::min_element(begin, end, [&value](const T& a, const T& b){
        return abs(value - a) < abs(value - b);
    });
}

auto a = find_nearest(l.begin(), l.end(), 42);
std::cout << *a << std::endl;

现场演示 find_nearest : http://ideone.com/g7dMYI


类似于 argmax 的高阶函数您问题中的函数可能如下所示:

template<typename Iter, typename Function>
Iter argmax(Iter begin, Iter end, Function f)
{
    typedef typename std::iterator_traits<Iter>::value_type T;
    return std::min_element(begin, end, [&f](const T& a, const T& b){
        return f(a) < f(b);
    });
}

您可以使用以下代码调用它,并具有您问题中的 lambda 函数:

auto a = argmax(l.begin(), l.end(), [](int x) { return -1 * abs(42 - x); });
std::cout << *a << std::endl;

现场演示 argmax : http://ideone.com/HxLMap


现在唯一剩下的区别是这个 argmax函数使用一个基于迭代器的接口(interface),它对应于 C++ 标准算法的设计 ( <algorithm> )。根据您使用的工具调整您自己的编码风格始终是个好主意。

如果你想要一个直接返回值的基于容器的接口(interface),Nawaz provided a nice solution这需要 decltype-feature 来正确指定返回类型。我决定以这种方式保留我的版本,以便人们可以看到两种可供选择的界面设计。

关于c++ - 需要 C++ 中非常通用的 argmax 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14199798/

相关文章:

c++ - 为什么不能像这样传递参数?

c# - 使用泛型变量作为参数调用重载函数

c++ - 对仅包含 0 和 1 的两个 vector 应用 or(||) 运算符

c++ - 使QWidget在点击后消失

c++ - 如何在只有 "makefile"而没有解决方案文件的 Visual Studio C++ 中编译开源框架?

c++ - 具有模板容器的协变返回类型

html - 返回 html 的 meteor 模板助手没有反应

C++ 模板和 STL vector 问题

scala - Scala 中的类型参数化对象

java - 泛型 - 使用 this 从另一个调用参数化构造函数