范围的最小返回值

时间:2017-02-16 12:44:37

标签: c++ algorithm c++11 c++14

我想知道是否有一个标准函数返回给定元素范围的返回值的最小值/最大值。像这样:

UserController

如果没有这样的话,这样的问题的最佳方法是什么? 我的列表很长,我真的不想复制它,也不想调用每个元素多次查找最小返回值的函数。谢谢!

更新

基于ForEveR建议使用std :: min_element,我做了以下基准测试:

std::vector<int> list = { -2, -1, 6, 8, 10 };
auto it = 
    std::find_min_return_value(list.begin(), list.end(), std::abs, std::less<int>);
// it should be the iterator for -1

这很好用:

std::vector<double> list = { -2, -1, 6, 8, 10 };
auto semi_expensive_test_function = [] (const double& a) { return asin(sin(a)); };
for(int i = 0; i < 10000000; ++i)
{
    auto it = std::min_element(list.begin(), list.end(), 
        [&] (const double& a, const double& b) mutable 
    {
        return(semi_expensive_test_function(a) < semi_expensive_test_function(b));
    });
}

修改代码后改为使用有状态lambda:

./a.out  11.52s user 0.00s system 99% cpu 11.521 total

结果:

for(int i = 0; i < 10000000; ++i)
{
    auto it = std::min_element(list.begin() + 1, list.end(), 
        [&, current_min_value = semi_expensive_test_function(*(list.begin()))] (const double& a, const double& b) mutable 
    {
        double current_value = semi_expensive_test_function(b);
        if(current_value < current_min_value)
        {
            current_min_value = std::move(current_value);
            return true;
        } 
        return false; 
    });
}

使用有状态的lambdas似乎是要走的路。问题是:是否有更复杂的代码方式来实现这一目标?

3 个答案:

答案 0 :(得分:2)

使用range-v3,它将类似于:

ranges::min(list, std::less<>{}, [](auto e) { return std::abs(e); });

答案 1 :(得分:1)

好吧,假设现在Boost就像标准库一样,你可以使用它:

#include <boost/range/adaptor/transformed.hpp>
#include <algorithm>

int main()
{
    std::vector<int> list = { -2, -1, 6, 8, 10 };
    auto abs_list = list | boost::adaptors::transformed(+[](int v) { return std::abs(v); });
    //                                                  ^ - read http://stackoverflow.com/questions/11872558/using-boost-adaptors-with-c11-lambdas
    auto it =  std::min_element(abs_list.begin(), abs_list.end(), std::less<int>{});
    std::cout << *it;
}

答案 2 :(得分:0)

如果它会被重用,并给你另一个选择,你可以按照std约定编写自己的通用算法。

template <typename T, typename ForwardIt, typename UnaryFunction, typename Comparator>
ForwardIt find_min_return_value(ForwardIt first, ForwardIt last, UnaryFunction op, Comparator compare)
{
    if (first == last)
        return last;

    ForwardIt smallestItr = first;
    T smallestValue = op(*first);

    for (auto itr = first + 1; itr != last; ++itr)
        {
        T current = op(*itr);
        if (compare(current, smallestValue))
            {
            smallestValue = current;
            smallestItr = itr;
            }
        }

    return smallestItr;
}

然后使用非常紧凑,并且每个元素只执行一次操作:

int main()
{
    std::vector<int> list = { -2, -1, 6, 8, 10 };
    auto it1 = find_min_return_value<int>(list.begin(), list.end(), [](int i){ return std::abs(i); }, std::less<int>());

    std::vector<std::string> strings = { "Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit" };
    auto it3 = find_min_return_value<size_t>(strings.begin(), strings.end(), [](std::string s){ return s.length(); }, std::less<size_t>());

    std::cout << *it1 << "\n"; // outputs -1
    std::cout << *it3 << "\n"; // outputs sit
}

如果你只怀疑它可能会在某一天重复使用,那么它可能不会,而且它过于复杂,应该只是一个简单的功能。