【问题标题】:Lambda function in accumulate累积中的 Lambda 函数
【发布时间】:2016-11-07 17:39:59
【问题描述】:

我正在尝试学习如何使用 Lamba 函数,并想做类似的事情:

给定一个向量 = {1,2,3,4,5}

我想要成对和的总和 = (1+2)+(2+3)+...

以下是我的尝试,但无法正常工作。

#include <vector>
#include <algorithm>

using namespace std;

vector <double> data = {1,10,100};

double mean = accumulate(data.begin(),data.end(),0.0);

double foo()
{
    auto bar = accumulate(data.begin(),data.end(),0.0,[&](int k, int l){return (k+l);});

    return bar
}

我尝试将 return 语句更改为 return (data.at(k)+data.at(l)),但效果不佳。

【问题讨论】:

    标签: c++ lambda accumulate


    【解决方案1】:

    添加成对和与将除第一个和最后一个元素之外的所有内容相加两次相同。不需要花哨的 lambda。

    auto result = std::accumulate(std::begin(data), std::end(data), 0.0)
      * 2.0 - data.front() - data.end();
    

    或者更安全一点:

    auto result = std::accumulate(std::begin(data), std::end(data), 0.0) 
       * 2.0 - (!data.empty() ? data.front() : 0) - (data.size() > 1 ? data.back() : 0);
    

    如果你坚持使用 lambda,你可以将加倍移到里面:

    result = std::accumulate(std::begin(data), std::end(data), 0.0, 
       [](double lhs, double rhs){return lhs + 2.0*rhs;}) 
       - data.front() - data.back();
    

    请注意,lambda 中的lhs当前总和,而不是序列中接下来的两个数字。

    如果您坚持在 lambda 中完成所有工作,您可以使用 generalized capture 跟踪索引:

    result = std::accumulate(std::begin(data), std::end(data), 0.0, 
           [currIndex = 0U, lastIndex = data.size()-1] (double lhs, double rhs) mutable
           {
              double result = lhs + rhs;
              if (currIndex != 0 && currIndex != lastIndex)
                 result += rhs;
              ++currIndex;
              return result;
           });
    

    Demo of all approaches

    【讨论】:

    • 哈,一些理论物理学家我没有在你的第一段中提出优雅的解决方案!那么确实不需要fancy lambda。也是演示的道具,仍然使用 lambda 编写解决方案,我现在可能不需要,但它很有启发性!
    【解决方案2】:

    您误解了std::accumulate 的工作原理。假设你有int array[],那么就可以累积:

    int value = initial_val;
    value = lambda( value, array[0] );
    value = lambda( value, array[1] );
    ...
    return value;
    

    这是伪代码,但应该很容易理解它的工作原理。因此,在您的情况下,std::accumulate 似乎不适用。您可以编写一个循环,或创建自己的特殊accumulate 函数:

    auto lambda = []( int a, int b ) { return a + b; };
    auto sum = 0.0;
    for( auto it = data.begin(); it != data.end(); ++it ) {
        auto itn = std::next( it );
        if( itn == data.end() ) break;
        sum += lambda( *it, *itn );
    }
    

    【讨论】:

    • 是的,我已经有一个使用for循环的工作代码,我只是认为使用accumulate可以更巧妙地捕获它,如果我想使用accumulate,我需要一个 lambda 函数来指定二元运算符。感谢您的反馈!
    【解决方案3】:

    您可以在 lambda 中捕获一个变量以保留最后一个值:

    #include <vector>
    #include <algorithm>
    #include <numeric>
    
    std::vector<double> data = {1,10,100};
    
    double mean = accumulate(data.begin(), data.end(), 0.0);
    
    double foo()
    {
        double last{0};
        auto bar = accumulate(data.begin(), data.end(), 0.0, [&](auto k, auto l) 
        {
            auto total = l + last; 
            last = l; 
            return total+k; 
        });
    
        return bar;
    }
    
    int main()
    {
        auto val = foo();
    }
    

    【讨论】:

    • 我现在没有你可以捕捉到最后,这实际上非常有用,谢谢!
    • 也许将变量 'mean' 重命名为 'sum' ?或者,包括除以 data.size() ?
    【解决方案4】:

    您可以使用某种索引,并添加下一个数字。

    size_t index = 1;
    auto bar = accumulate(data.begin(), data.end(), 0.0, [&index, &data](double a, double b) {
        if (index < data.size())
            return a + b + data[index++];
        else 
            return a + b;
    });
    

    请注意,您有一个 doubles 向量,但使用 ints 求和。

    【讨论】:

      猜你喜欢
      • 2018-05-13
      • 2021-10-14
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      • 2012-07-18
      • 2012-05-31
      • 2016-02-19
      • 1970-01-01
      相关资源
      最近更新 更多