【C++】accumulate – reduce関数の実現【関数型プログラミング】

C++の標準ライブラリにはreduce関数やinject関数、fold関数が存在しません。代わりに別機能による代替処理を紹介します。なおC++標準ライブラリのreduce関数はC++17以降の規格で利用可能になる予定です。

accumulate

accumulateテンプレート関数は範囲要素の集計を実現する機能です。これによってreduce関数やfold関数の挙動が実現できます。

第一引数と第二引数に要素範囲を指定します。第三引数には集計の際の初期値を指定します。accumulateの戻り値型はこの初期値の型と同じものになります。

// #include <numeric> // accumulate
std::vector<int> v = {1, 2, 3};

int sum = std::accumulate(v.begin(), v.end(), int(0));
sum; // 結果: 6

内部的には次のような処理が行われることになります。

int sum = (((int(0) + 1) + 2) + 3);

accumulate関数では、指定された初期値を基準に、要素範囲に対して順番に二項演算が適用されていきます。各二項演算の結果は、次の要素への二項演算適用時の左項となります。なお先頭要素の場合は第三引数に指定された初期値が左項となります。

なお、二項演算のデフォルトはoperator+演算子による加算処理ですが、第四引数に独自の二項演算処理を指定することも可能です。

std::vector<int> v = {1, 2, 3};
std::accumulate(v.begin(), v.end(), 10, [](int a, int b) {
   return a - b;
}); // 結果: 4 (((10 - 1) - 2) - 3)
// #include <functional> // multiplies: 乗算
using namespace std;

int w[] = {2, 3, 4};
int v = accumulate(w, end(w), 1, multiplies<>());
v;  // 結果: 24

string s = accumulate(w, end(w), string(""), [](string a, int b) {
   return a + to_string(b);
}); // 結果: "234"

ちなみに、accumulate関数はalgorithmヘッダではなくnumericヘッダに定義されている点に注意してください。

reduce関数の実現

accumulateを扱いやすくしたものです。ご自由にお使い下さい。

template<class Container, class InitialT, class BinaryOp>
InitialT reduce(const Container& c, InitialT v, BinaryOp op) {
  using std::begin;
  using std::end;
  return std::accumulate(begin(c), end(c), v, op);
}
std::vector<int> v = {1, 2, 3};
assert('G' == reduce(v, 'A', [](char L, int R) { return L + R; }));

広告