nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

C++で関数型プログラミング (filter関数の実装)

はじめに

C++で、関数型プログラミングでいうfilter関数(抽出の処理を行う関数のこと)を使う場合は、以下のテンプレート関数を使うといいです。

  • copy_if
  • remove_copy_if

コード例

以下のコード例では、ラムダ式と挿入イテレータが使用されています。

挿入イテレータ(insert iterator)は、イテレータに対する代入処理を挿入処理に置き換える特殊な出力イテレータです。

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;


void getCharVector(std::vector<char> &someVector, const std::string someString)
{
    // 1文字つずつ取り出してvector<char>に格納する
    for (auto var : someString)
    {
        someVector.push_back(var);
    }
}


int main(void)
{
    std::vector<char> temp;

    getCharVector(temp, "a1a2a3a4a5a6a7a8a9a10");

    std::vector<char> filtered;

    // copy_ifテンプレート関数は、条件を満たした要素のみをコピーする機能
    std::copy_if(temp.begin(), temp.end(), std::back_inserter(filtered), [](char c) { return c == 'a'; });

    std::for_each(filtered.begin(), filtered.end(), [](char c) {std::cout << c << std::endl; });

    // std::count_if とは、第3引数で与えられる単項関数(Unary function)の条件を満たす要素が配列やコンテナにいくつ含まれているか返すテンプレート関数
    int sum = std::count_if(temp.begin(), temp.end(), [](char c) { return c == 'a'; });

    std::cout << "total : " << sum << std::endl;
}
a
a
a
a
a
a
a
a
a
a
total : 10

template関数でfilter関数の実装

template関数を使えば、数列で文字列でも、同じfilter関数で処理できます。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cassert>

template<class Container, class Predicate>
Container filter(const Container& c, Predicate f) {
    Container r;
    std::copy_if(begin(c), end(c), std::back_inserter(r), f);
    return r;
}

int main(void)
{
    // 配列をfileter template関数に渡す
    auto target = filter(std::vector<int>{2, 3, 4}, [](int i) { return i < 4; });
    
    for (auto var : target)
    {
        std::cout << var << std::endl;
    }
    
    // std::vector::back関数は末尾要素への参照を取得する関数
    assert(3 == target.back());
    
    // 文字列をfileter template関数に渡す
    auto targetString = filter(std::string("a::b_c()"), isalpha);
    
    // 変数の方を調べます(std::string型で返ってきます)    
    std::cout << typeid(targetString).name() << std::endl;
    
    for (auto var : targetString)
    {
        std::cout << var << std::endl;
    }
    
    assert("abc" == targetString);
}
2
3
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
a
b
c

リンク