2016-11-07 3 views
1

Ich versuche zu lernen, wie lamba Funktionen zu nutzen, und wie etwas zu tun:Lambda-Funktion in accumulate

Bei einem Vektor = {1,2,3,4,5}

I will die Summe der paarweisen Summen = (1 + 2) + (2 + 3) + ...

Unten ist mein Versuch, der nicht richtig funktioniert.

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

Ich versuchte, die return-Anweisung zu ändern zurückzukehren (data.at (k) + data.at (l)), die recht funktioniert nicht.

Antwort

3

Das Hinzufügen paarweiser Summen ist das Gleiche wie das Summieren über alles zweimal mit Ausnahme der ersten und letzten Elemente. Keine Notwendigkeit für ein schickes Lambda.

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

Oder ein wenig sicherer:

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

Wenn Sie auf einem Lambda bestehen, können Sie die Verdoppelung innen bewegen:

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

Beachten Sie, dass lhs innerhalb der Lambda die Strom Summe, nicht die nächsten zwei Zahlen in der Sequenz.

Wenn Sie darauf bestehen, innerhalb der Lambda die ganze Arbeit zu tun, können Sie einen Index nachbilden generalized capture unter Verwendung:

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

+1

Hah, ich bin ein theoretischer Physiker, ich habe nicht die elegante Lösung in Ihrem ersten Absatz! Dann gibt es in der Tat keine Notwendigkeit für _fancy lambda_. Unterstützt auch Demos und schreibt immer noch eine Lösung mit Lambda, die ich wahrscheinlich jetzt nicht brauche, aber es ist lehrreich! – storluffarn

2

Sie missverstehen, wie std::accumulate funktioniert. Angenommen, Sie int array[] haben, dann sammelt sich:

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

dies ist Pseudo-Code, aber es sollte ziemlich einfach sein, zu verstehen, wie es funktioniert. Also in Ihrem Fall scheint std::accumulate nicht anwendbar zu sein. Sie können eine Schleife schreiben, oder Ihre eigene spezielle accumulate Funktion erstellen:

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); 
} 
+0

Ja, ich hatte einen funktionierenden Code mit einem 'for' Schleife bereits Ich dachte nur, dass alles mit "accumulate" sauberer erfasst werden könnte und dass, wenn ich "accumulate" verwenden wollte, ich eine Lambda-Funktion brauchte, um den binären Operator anzugeben. Vielen Dank für Ihr Feedback! – storluffarn

1

Sie eine Variable in dem Lambda erfassen könnten den letzten Wert zu halten:

#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(); 
} 
+0

konnte ich jetzt nicht mehr erfassen, das ist eigentlich sehr nützlich, danke! – storluffarn

1

Sie irgendeine Art von Index verwenden könnten, und füge die nächste Nummer hinzu.

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

Note haben Sie einen Vektor von double s aber verwenden int s zu summieren.

Verwandte Themen