最終更新日時:
が更新

履歴 編集

リスト処理の遅延評価

Boost Range LibraryのRangeアダプタは、リスト処理を遅延評価する仕組みを提供する。

インデックス

条件抽出 - filtered

リストから値の条件抽出をするには、boost::adaptors::filteredを使用する。

以下は、{1, 2, 3, 4, 5}というリストから、偶数値のみを抽出している。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm/for_each.hpp>

using namespace boost::adaptors;

bool is_even(int x) { return x % 2 == 0; }
void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    boost::for_each(v | filtered(is_even), disp);
}

実行結果:

2
4

値の変換 - transformed

リストの全ての要素に関数を適用するには、boost::adaptors::transformedを使用する。

これは、関数型言語一般でのmap関数に相当する。

以下は、リストの全ての要素に1を加算する処理である。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/for_each.hpp>

using namespace boost::adaptors;

int add(int x) { return x + 1; }
void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    boost::for_each(v | transformed(add), disp);
}

実行結果:

2
3
4
5
6

型変換 - transformed

リストの全ての要素に関数を適用するboost::adaptors::transformedは、型変換にも使用することができる。

以下は、リストの全ての要素をintからstd::stringに変換する処理である。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/lexical_cast.hpp>

using namespace boost::adaptors;

std::string int_to_string(int x) { return boost::lexical_cast<std::string>(x); }

void disp(const std::string& s) { std::cout << s << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    boost::for_each(v | transformed(int_to_string), disp);
}

実行結果:

1
2
3
4
5

逆順に走査する - reversed

リストを逆順に走査するには、boost::adaptors::reversedを使用する。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm/for_each.hpp>

using namespace boost::adaptors;

void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    boost::for_each(v | reversed, disp);
}

実行結果:

5
4
3
2
1

mapのキーのみを抽出する - map_keys

std::mapboost::unordered_mapstd::vector<std::pair<Key, Value> >のようなコンテナからキーのみを抽出するには、boost::adaptors::map_keysを使用する。

#include <iostream>
#include <map>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/for_each.hpp>

using namespace boost::adaptors;

void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::map<int, std::string> m = boost::assign::map_list_of
        (3, "Alice")
        (1, "Bob")
        (4, "Carol")
        ;

    boost::for_each(m | map_keys, disp);
}

実行結果:

1
3
4

mapの値のみを抽出する - map_values

std::mapboost::unordered_mapstd::vector<std::pair<Key, Value> >のようなコンテナから値のみを抽出するには、boost::adaptors::map_valuesを使用する。

#include <iostream>
#include <map>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/for_each.hpp>

using namespace boost::adaptors;

void disp(const std::string& s) { std::cout << s << std::endl; }

int main()
{
    const std::map<int, std::string> m = boost::assign::map_list_of
        (3, "Alice")
        (1, "Bob")
        (4, "Carol")
        ;

    boost::for_each(m | map_values, disp);
}

実行結果:

Bob
Alice
Carol

2つのリストを連結する - join

リストを連結するには、boost::join()関数を使用する。

この関数は、2つのリストを連結した新たなリストを返すのではなく、1つのリストの走査が終わったら2つめのリストを走査するRangeを返す。

#include <iostream>
#include <vector>
#include <list>
#include <boost/assign/list_of.hpp>
#include <boost/range/join.hpp>
#include <boost/range/algorithm/for_each.hpp>

void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3);
    const std::list<int> ls = boost::assign::list_of(4)(5);

    boost::for_each(boost::join(v, ls), disp);
}

実行結果:

1
2
3
4
5

値の範囲を生成する - irange

{1..5}のような連続した値の範囲を生成する場合には、boost::irange()関数を使用する。

この関数に値の範囲を引数として渡すことで、その値の範囲を走査可能なRandom Access Rangeを返す。

#include <iostream>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm/for_each.hpp>

void disp(int x) { std::cout << x << std::endl; }

int main()
{
    // [1, 5)の範囲を生成する
    boost::for_each(boost::irange(1, 5), disp);
}

実行結果:

1
2
3
4

また、irangeには、第3引数として、値を進めるステップ値も指定することができる。

これを指定することで、「値を2ずつ進める」といったことが可能になる。

#include <iostream>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm/for_each.hpp>

void disp(int x) { std::cout << x << std::endl; }

int main()
{
    // [1, 10)の範囲を、2ずつ進める
    boost::for_each(boost::irange(1, 10, 2), disp);
}

実行結果:

1
3
5
7

リストに対する複数の遅延処理を合成する

Boost Range LibraryのRangeアダプタは、個々の処理を遅延評価するだけでなく、operator|()でさらに繋ぎ、それらの処理を合成できる。

以下は、条件抽出(filtered)と関数適用(transformed)を合成する処理である。リストが実際に走査されそれらの処理が必要になるまで評価が遅延される。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/for_each.hpp>

using namespace boost::adaptors;

bool is_even(int x) { return x % 2 == 0; }
int add(int x) { return x + 1; }

void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    boost::for_each(v | filtered(is_even) | transformed(add), disp);
}

実行結果:

3
5