Search on the blog

2013年11月10日日曜日

C++で関数型プログラミング

前も同じようなことした気がしますが、C++11でcopy_ifと無名関数が使えるようになったので改めて遊んでみました。
  1. map
  2. reduce
  3. filter
に相当する処理をC++の標準機能で書いてみました。

map的なこと
map的なことはtransformで出来ます。あまり面白いことはやってませんが、最後のフィボナッチ数列はおもしろいと思います(もっとクールな書き方がありそうですが)。
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

template<typename T>
void disp(const vector<T> &x) {
    for (size_t i = 0; i < x.size(); i++)
        cout << x[i] << " ";
    cout << endl;
}

int main(int argc, char **argv) {
    vector<int> a;
    for (int i = 0; i < 10; i++)
        a.push_back(i);

    // 二乗を計算
    transform(a.begin(), a.end(), a.begin(), [](int x) {return x*x;});
    disp(a);   // 0 1 4 9 16 25 36 49 64 81

    // 入力と出力の型が違ってもOK
    vector<char> b;
    transform(a.begin(), a.end(), back_inserter(b), [](int x){return 'A'+x%26;});
    disp(b);   // A B E J Q Z K X M D 

    // フィボナッチ数列
    vector<int> fib(20, 1);
    transform(fib.begin(), fib.end()-2, fib.begin()+1, fib.begin()+2, [](int x, int y) {return x+y;});
    disp(fib);  // 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 

    return 0;
}

reduce的なこと
reduce的なことはaccumulateで出来ます。この関数は以前はnumericライブラリにいたのですが、C++11からはalgorithmに移動(※numericからのインクルードでも使える)したみたいです。
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char **argv) {
    // 和を計算
    vector<int> a;
    for (int i = 0; i < 10; i++)
        a.push_back(i);
    cout << accumulate(a.begin(), a.end(), 1000) << endl;   // 1045

    // 文字列にも使える(+オペレータは文字の連結)
    vector<string> b;
    b.push_back("hello, ");
    b.push_back("world");
    b.push_back("!!");
    cout << accumulate(b.begin(), b.end(), string("")) << endl;   // hello, world!!

    // 二項演算子を指定
    cout << accumulate(a.begin(), a.end(), 1, [](int x, int y){return max(x, y);}) << endl; // 9

    return 0;
}

filter的なこと
filter的なことはcopy_ifで出来ます。copy_ifはC++11から追加された標準関数です。
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

template<typename T>
void disp(const vector<T> &x) {
    for (size_t i = 0; i < x.size(); i++)
        cout << x[i] << " ";
    cout << endl;
}
 
int main(int argc, char **argv) {
    vector<int> a;
    for (int i = -5; i <= 5; i++)
        a.push_back(i);

    // 偶数のみ抽出
    vector<int> b;   
    copy_if(a.begin(), a.end(), back_inserter(b), [](int x) {return x % 2 == 0;});
    disp(b);      // -4 -2 0 2 4 

    // 負の数のみ抽出
    vector<int> c;   
    copy_if(a.begin(), a.end(), back_inserter(c), [](int x) {return x < 0;});
    disp(c);      // -5 -4 -3 -2 -1 

    return 0;
}

0 件のコメント:

コメントを投稿