要素を一列に並べたデータ構造を「シーケンス (sequence)」とか「列」と呼びます。たとえば、Common Lisp はリスト、一次元配列 (ベクタ)、文字列を列型データとして統一して扱うことができます。列を操作する関数を列関数といい、Common Lisp には便利な列関数が多数用意されています。
C++の場合、vector, array, list, forward_list などのコンテナクラスは、シーケンスとして共通な操作を考えることができます。今回はシーケンスを操作する関数をテンプレートで作ってみましょう。
シーケンスの中から最大値を求める関数 maximum と、最小値を求める関数 minimum を定義してください。引数は先頭と終端を示すイテレータで、返り値は求めた要素へのイテレータとします。
シーケンスを線形探索する関数 member, position, count を定義してください。member の返り値は bool、position の返り値は見つけた位置 (見つからない場合は -1)、count の返り値は見つけた要素の個数です。
引数の叙述関数が真を返すデータを線形探索する高階関数 member_if, position_if, count_if を定義してください。
シーケンスの要素に引数の関数オブジェクト func を適用して、その結果を新しいシーケンスに格納して返す高階関数 mapcar を定義してください。このような操作を「マッピング (写像)」といいます。
引数 x と等しい要素をシーケンスから削除する関数 remove と、叙述関数が真を返す要素をシーケンスから削除する関数 remove_if を定義してください。なお、どちらの関数も引数にはシーケンスのイテレータ (始点と終点) を受け取り、シーケンスを破壊的に修正することにします。返り値は最後に書き込んだ要素の次を示すイテレータです。
シーケンスの要素を先頭から畳み込む高階関数 fold_left と末尾から畳み込む fold_right を定義してください。
シーケンスの要素に叙述関数 p を適用し、一つでも真を返す要素があれば真を返す関数 any と、一つでも偽を返す要素があれば偽を返す (全てが真の場合に真を返す) 関数 every を定義してください。
シーケンスに整数 n から始まる数列をセットする関数 iota と、n から始まる数列の要素に関数 f を適用して、その結果をシーケンスにセットする高階関数 tabulate を定義してください。
引数 x と等しいシーケンスの要素を引数 y に置換する関数 substitute と、叙述関数が真を返す要素を引数 y に置換する関数 substitute_if を定義してください。なお、これらの関数は引数のシーケンスを破壊的に修正するものとします。
「連想リスト (association list : a-list)」は Lisp でよく用いられるデータ構造で、キーとデータの組を要素とする連結リストで実現することができます。
┌────┬────┬────┬──→ データ
│ │ │ │
連想リスト => [("a", 1), ("b", 2), ("c", 3), ("d", 4)]
│ │ │ │
└────┴────┴────┴──→ キー
図 : 連想リストの構造
上図の場合、文字列 "a", "b", "c", "d" がキーで、整数 1, 2, 3, 4 がデータとなります。C++の場合、連想リストは list<pair<K, V>> で表すことができます。また、他のコンテナクラスを使っても簡単に実装することができます。
連想リストの先頭にキーと値を追加する関数 acons と、連想リストからキーを線形探索する関数 assoc を定義してください。
リスト : 最大値と最小値
template<class It>
It maximum(It first, It last)
{
if (first == last) return last;
It m = first++;
while (first != last) {
if (*m < *first) m = first;
++first;
}
return m;
}
template<class It>
It minimum(It first, It last)
{
if (first == last) return last;
It m = first++;
while (first != last) {
if (*m > *first) m = first;
++first;
}
return m;
}
どちらの関数も引数 first から last までの区間から最大値 (または最小値) を探します。これ以降、シーケンスの区間を [first, last) と記述することにします。first と last が等しい場合は last を返します。そして、先頭要素へのイテレータを変数 m にセットして、first を次の要素へ進めます。あとは、while ループで要素を順番にチェックしていき、*m よりも *frist が大きい (または小さい) 場合は m を first に書き換えます。最後に m を返すだけです。
なお、STL の algorithm には同等の機能を持つ関数 max_element と min_element が用意されています。
探索する区間をイテレータ [first, last) で渡すことにすると、プログラムは次のようになります。
リスト : シーケンスの線形探索 (1)
template<class It, class T>
bool member(It first, It last, const T& val)
{
while (first != last)
if (*first++ == val) return true;
return false;
}
template<class It, class T>
int position(It first, It last, const T& val)
{
int i = 0;
while (first != last) {
if (*first++ == val) return i;
i++;
}
return -1;
}
template<class It, class T>
int count(It first, It last, const T& val)
{
int c = 0;
while (first != last)
if (*first++ == val) c++;
return c;
}
テンプレート仮引数の It がイテレータ、T が探索するデータの型を表します。member は *first と val が等しければ true を返します。postion は位置 (添字) i を返します。count は *first と val が等しければ変数 c を +1 して、最後に c を返します。
シーケンス自身をそのまま渡すこともできます。次のリストを見てください。
リスト : シーケンスの線形探索 (2)
template<class T, class U>
bool member(const T& seq, const U& val)
{
for (auto& x : seq)
if (x == val) return true;
return false;
}
template<class T, class U>
int position(const T& seq, const U& val)
{
int i = 0;
for (auto& x : seq) {
if (x == val) return i;
i++;
}
return -1;
}
template<class T, class U>
int count(const T& seq, const U& val)
{
int c = 0;
for (auto& x : seq)
if (x == val) c++;
return c;
}
T がシーケンスのデータ型を表す仮引数で、U が探索するデータの型です。シーケンスの要素は範囲 for 文で順番に取り出すことができます。データ型の指定も auto を使えば簡単です。関数型言語の場合、このような仕様が一般的ですが、C++ではイテレータを渡すのが普通のようです。
リスト : 線形探索 (高階関数版)
template<class It, class F>
bool member_if(It first, It last, F func)
{
while (first != last)
if (func(*first++)) return true;
return false;
}
template<class It, class F>
int position_if(It first, It last, F func)
{
int i = 0;
while (first != last) {
if (func(*first++)) return i;
i++;
}
return -1;
}
template<class It, class F>
int count_if(It first, It last, F func)
{
int c = 0;
while (first != last)
if (func(*first++)) c++;
return c;
}
It がイテレータを表す仮引数、F が関数オブジェクトを表す仮引数です。区間 [first, last) から叙述関数 func が真を返す要素を探索します。member_if は func(*first) が真ならば true を返します。positon_if は位置 (添字) i を返します。count_if は変数 c の値を +1 して、最後に c を返します。
シーケンス自身を渡す場合は次のようになります。
リスト : 線形探索 (高階関数版)
template<class T, class F>
bool member_if(const T& seq, F func)
{
for (auto& x : seq)
if (func(x)) return true;
return false;
}
template<class T, class F>
int position_if(const T& seq, F func)
{
int i = 0;
for (auto& x : seq)
if (func(x)) return i;
return -1;
}
template<class T, class F>
int count_if(const T& seq, F func)
{
int c = 0;
for (auto& x : seq)
if (func(x)) c++;
return c;
}
func(x) が真を返すとき、member_if は true を返し、position_if は変数 i を返し、count_if は変数 c を +1 して、最後に c を返します。
リスト : マッピング
template<class T, class F>
T mapcar(const T& seq, F func)
{
T new_seq(seq.size());
auto iter = new_seq.begin();
for (auto& x : seq)
*iter++ = func(x);
return new_seq;
}
最初に、コンストラクタで大きさ seq.size() の新しいシーケンス new_seq を生成します。そして、新しいシーケンスの先頭要素を示すイテレータ iter を生成します。あとは範囲 for 文でシーケンス seq から要素 x を取り出し、*iter に func(x) の返り値をセットします。最後に new_seq を返します。
メンバ関数に push_back があるならば、空の新しいシーケンスを生成して、そこに push_back で追加していく方法もあります。ただし、forward_list には push_back がないので、今回はこのようなプログラムにしてみました。
シーケンスをイテレータで渡す場合は次のようになります。
リスト : マッピングの別解
template<class It, class F>
It mapcar(It first, It last, F func, It result)
{
while (first != last)
*result++ = func(*first++);
return result;
}
引数 result は結果を格納するシーケンスへのイテレータです。この場合、mapcar を呼び出す前に出力先のシーケンスを生成しておいてください。
リスト : 要素の削除
template<class It, class U>
It remove(It first, It last, const U& val)
{
It result = first;
while (first != last) {
if (*first != val) *result++ = *first;
++first;
}
return result;
}
remove は区間 [first, last) の中から val と等しい要素を削除します。変数 result は書き込む位置を表すイテレータで、first に初期化します。あとは、*first と val が等しくなければ、*resulte に *first をセットするだけです。区間を上書きすることに注意してください。最後に result を返します。つまり、区間 [first, result) に要素を削除した結果がセットされます。
リスト : 要素の削除 (高階関数版)
template<class It, class F>
It remove_if(It first, It last, F func)
{
It result = first;
while (first != last) {
if (!func(*first)) *result++ = *first;
++first;
}
return result;
}
remove_if は叙述関数 func が真を返す要素を削除します。処理は remove とほとんど同じです。なお、STL の algorithm には同等の機能を持つ関数 remove, remove_if が用意されています。
リスト : 畳み込み
template<class T, class U, class F>
U fold_left(const T& seq, U init, F func)
{
for (auto& x : seq) init = func(init, x);
return init;
}
template<class T, class U, class F>
U fold_right(const T& seq, U init, F func)
{
for (auto iter = seq.crbegin(); iter != seq.crend(); ++iter)
init = func(*iter, init);
return init;
}
テンプレート仮引数 T がシーケンスのデータ型、U が初期値のデータ型、F が 2 引数の関数オブジェクトを表します。fold_left は範囲 for 文を使えば簡単です。init の値を func(init, x) で書き換えていくだけです。fold_right は reverse イテレータを使います。なお、forward_list は reverse イテレータをサポートしていないので、fold_right を適用することはできません。
func の引数は fold_left と fold_right で逆になっていることに注意してください。なお、畳み込み fold_left と fold_right の仕様は、プログラミング言語によって異なります。関数型言語でも統一されているわけではありません。ご注意くださいませ。
イテレータを渡す場合は次のようになります。
リスト : 別解
template<class It, class T, class F>
T fold(It first, It last, T init, F func)
{
while (first != last) init = func(init, *first++);
return init;
}
とくに難しいところはないと思います。
リスト : any と every
template<class It, class F>
bool any(It first, It last, F func)
{
while (first != last)
if (func(*first++)) return true;
return false;
}
template<class It, class F>
bool every(It first, It last, F func)
{
while (first != last)
if (!func(*first++)) return false;
return true;
}
どちらの関数もイテレータ [first, last) が表す区間の要素に関数オブジェクト func を適用し、any は真を返す要素がひとつでもあれば true を返します。every は偽を返す要素が一つでもあれば false を返します。C++の algorithm には同等の機能を持つ関数 any_of と all_of が用意されています。
シーケンス自身を渡す場合は次のようになります。
リスト : 別解
template<class T, class F>
bool any(const T& seq, F func)
{
for (auto& x : seq)
if (func(x)) return true;
return false;
}
template<class T, class F>
bool every(const T& seq, F func)
{
for (auto& x : seq)
if (!func(x)) return false;
return true;
}
範囲 for 文を使えば簡単にプログラムすることができます。
リスト : iota と tabulate
template<class T>
void iota(T& seq, int n)
{
for (auto& x : seq) x = n++;
}
template<class T, class F>
void tabulate(T& seq, int n, F func)
{
for (auto& x : seq) x = func(n++);
}
iota は範囲 for 文で要素への参照 x に整数値 n をセットしていくだけです。tabulate は func(n++) をセットしていくだけです。なお、C++ (C++11) の STL numeric には同等の機能を持つ関数 iota が用意されています。
シーケンスをイテレータ [first, last) で渡す場合は次のようになります。
リスト : シーケンスの置換
template<class It, class U>
void substitute(const U& x, const U& y, It first, It last)
{
while (first != last) {
if (*first == x) *first = y;
first++;
}
}
template<class It, class U, class F>
void substitute_if(F func, const U& y, It first, It last)
{
while (first != last) {
if (func(*first)) *first = y;
first++;
}
}
substitute は *frist と引数 x が等しいとき、*first に引数 y を代入します。substitute_if は func(*first) が真を返すとき、*first に y を代入します。
シーケンス自身を渡す場合は次のようになります。
リスト : 別解
template<class T, class U>
void substitute(const U& x, const U& y, T& seq)
{
for (auto& z : seq) {
if (z == x) z = y;
}
}
template<class T, class U, class F>
void substitute_if(F func, const U& y, T& seq)
{
for (auto& x : seq) {
if (func(x)) x = y;
}
}
どちらの関数も範囲 for 文を使うと簡単にプログラムすることができます。
リスト : 連想リスト
template<class K, class V, class T>
void acons(const K& key, const V& val, T& seq)
{
seq.emplace_front(key, val);
}
template<class K, class It>
It assoc(const K& key, It first, It last)
{
while (first != last) {
if (first->first == key) return first;
++first;
}
return first;
}
テンプレート仮引数の K がキーを、V が値を表します。acons は emplace_front を使うと簡単です。これで、シーケンスの先頭にキーと値の組を追加することができます。assoc はイテレータ [first, last) の中からキー key を探索し、見つけたらその組を指し示すイテレータを返します。見つからない場合は last を返します。
//
// yacp3.cpp : Yet Another C++ Problems (3)
//
// Copyright (C) 2015-2023 Makoto Hiroi
//
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// Q21 最大値と最小値
template<class It>
It maximum(It first, It last)
{
if (first == last) return last;
It m = first++;
while (first != last) {
if (*m < *first) m = first;
++first;
}
return m;
}
template<class It>
It minimum(It first, It last)
{
if (first == last) return last;
It m = first++;
while (first != last) {
if (*m > *first) m = first;
++first;
}
return m;
}
// Q22
template<class T, class U>
bool member(const T& seq, const U& val)
{
for (auto& x : seq)
if (x == val) return true;
return false;
}
template<class It, class T>
bool member(It first, It last, const T& val)
{
while (first != last)
if (*first++ == val) return true;
return false;
}
template<class T, class U>
int position(const T& seq, const U& val)
{
int i = 0;
for (auto& x : seq) {
if (x == val) return i;
i++;
}
return -1;
}
template<class It, class T>
int position(It first, It last, const T& val)
{
int i = 0;
while (first != last) {
if (*first++ == val) return i;
i++;
}
return -1;
}
template<class T, class U>
int count(const T& seq, const U& val)
{
int c = 0;
for (auto& x : seq)
if (x == val) c++;
return c;
}
template<class It, class T>
int count(It first, It last, const T& val)
{
int c = 0;
while (first != last)
if (*first++ == val) c++;
return c;
}
// Q23
template<class T, class F>
bool member_if(const T& seq, F func)
{
for (auto& x : seq)
if (func(x)) return true;
return false;
}
template<class It, class F>
bool member_if(It first, It last, F func)
{
while (first != last)
if (func(*first++)) return true;
return false;
}
template<class T, class F>
int position_if(const T& seq, F func)
{
int i = 0;
for (auto& x : seq)
if (func(x)) return i;
return -1;
}
template<class It, class F>
int position_if(It first, It last, F func)
{
int i = 0;
while (first != last) {
if (func(*first++)) return i;
i++;
}
return -1;
}
template<class T, class F>
int count_if(const T& seq, F func)
{
int c = 0;
for (auto& x : seq)
if (func(x)) c++;
return c;
}
template<class It, class F>
int count_if(It first, It last, F func)
{
int c = 0;
while (first != last)
if (func(*first++)) c++;
return c;
}
// Q24
template<class T, class F>
T mapcar(const T& seq, F func)
{
T new_seq(seq.size());
auto iter = new_seq.begin();
for (auto& x : seq)
*iter++ = func(x);
return new_seq;
}
template<class It, class F>
It mapcar(It first, It last, F func, It result)
{
while (first != last)
*result++ = func(*first++);
return result;
}
// Q25
template<class It, class U>
It remove(It first, It last, const U& val)
{
It result = first;
while (first != last) {
if (*first != val) *result++ = *first;
++first;
}
return result;
}
template<class It, class F>
It remove_if(It first, It last, F func)
{
It result = first;
while (first != last) {
if (!func(*first)) *result++ = *first;
++first;
}
return result;
}
// Q26
template<class T, class U, class F>
U fold_left(const T& seq, U init, F func)
{
for (auto& x : seq) init = func(init, x);
return init;
}
template<class T, class U, class F>
U fold_right(const T& seq, U init, F func)
{
for (auto iter = seq.crbegin(); iter != seq.crend(); ++iter)
init = func(*iter, init);
return init;
}
template<class It, class T, class F>
T fold(It first, It last, T init, F func)
{
while (first != last) init = func(init, *first++);
return init;
}
// Q27
template<class T, class F>
bool any(const T& seq, F func)
{
for (auto& x : seq)
if (func(x)) return true;
return false;
}
template<class It, class F>
bool any(It first, It last, F func)
{
while (first != last)
if (func(*first++)) return true;
return false;
}
template<class T, class F>
bool every(const T& seq, F func)
{
for (auto& x : seq)
if (!func(x)) return false;
return true;
}
template<class It, class F>
bool every(It first, It last, F func)
{
while (first != last)
if (!func(*first++)) return false;
return true;
}
// Q28
template<class T>
void iota(T& seq, int n)
{
for (auto& x : seq) x = n++;
}
template<class T, class F>
void tabulate(T& seq, int n, F func)
{
for (auto& x : seq) x = func(n++);
}
// Q29
template<class T, class U>
void substitute(const U& x, const U& y, T& seq)
{
for (auto& z : seq) {
if (z == x) z = y;
}
}
template<class It, class U>
void substitute(const U& x, const U& y, It first, It last)
{
while (first != last) {
if (*first == x) *first = y;
first++;
}
}
template<class T, class U, class F>
void substitute_if(F func, const U& y, T& seq)
{
for (auto& x : seq) {
if (func(x)) x = y;
}
}
template<class It, class U, class F>
void substitute_if(F func, const U& y, It first, It last)
{
while (first != last) {
if (func(*first)) *first = y;
first++;
}
}
// Q30 連想リスト (emplace_front が必要)
template<class K, class V, class T>
void acons(const K& key, const V& val, T& seq)
{
seq.emplace_front(key, val);
}
template<class K, class It>
It assoc(const K& key, It first, It last)
{
while (first != last) {
if (first->first == key) return first;
++first;
}
return first;
}
template<class T>
void print_seq(const T& seq)
{
for (auto& x : seq) cout << x << " ";
cout << endl;
}
bool is_even(int x) { return x % 2 == 0; }
bool is_odd(int x) { return x % 2 != 0; }
int square(int x) { return x * x; }
int main()
{
vector<int> a = {1, 3, 5, 7, 9};
list<int> b = {2, 4, 6, 8, 10};
cout << "-- maximum --\n";
auto m1 = maximum(a.begin(), a.end());
cout << *m1 << endl;
auto m2 = maximum(b.begin(), b.end());
cout << *m2 << endl;
cout << "-- minimum --\n";
auto m3 = minimum(a.begin(), a.end());
cout << *m3 << endl;
auto m4 = minimum(b.begin(), b.end());
cout << *m4 << endl;
cout << "-- member --\n";
cout << member(a, 1) << endl;
cout << member(a, 10) << endl;
cout << member(b, 1) << endl;
cout << member(b, 10) << endl;
cout << member(a.begin(), a.end(), 1) << endl;
cout << member(a.begin(), a.end(), 10) << endl;
cout << member(b.begin(), b.end(), 1) << endl;
cout << member(b.begin(), b.end(), 10) << endl;
cout << "-- position--\n";
cout << position(a, 1) << endl;
cout << position(a, 10) << endl;
cout << position(b, 1) << endl;
cout << position(b, 10) << endl;
cout << position(a.begin(), a.end(), 1) << endl;
cout << position(a.begin(), a.end(), 10) << endl;
cout << position(b.begin(), b.end(), 1) << endl;
cout << position(b.begin(), b.end(), 10) << endl;
cout << "-- count --\n";
cout << count(a, 1) << endl;
cout << count(a, 10) << endl;
cout << count(b, 1) << endl;
cout << count(b, 10) << endl;
cout << count(a.begin(), a.end(), 1) << endl;
cout << count(a.begin(), a.end(), 10) << endl;
cout << count(b.begin(), b.end(), 1) << endl;
cout << count(b.begin(), b.end(), 10) << endl;
cout << "-- member_if --\n";
cout << member_if(a, is_even) << endl;
cout << member_if(a, is_odd) << endl;
cout << member_if(b, is_even) << endl;
cout << member_if(b, is_odd) << endl;
cout << member_if(a.begin(), a.end(), is_even) << endl;
cout << member_if(a.begin(), a.end(), is_odd) << endl;
cout << member_if(b.begin(), b.end(), is_even) << endl;
cout << member_if(b.begin(), b.end(), is_odd) << endl;
cout << "-- position_if --\n";
cout << position_if(a, is_even) << endl;
cout << position_if(a, is_odd) << endl;
cout << position_if(b, is_even) << endl;
cout << position_if(b, is_odd) << endl;
cout << position_if(a.begin(), a.end(), is_even) << endl;
cout << position_if(a.begin(), a.end(), is_odd) << endl;
cout << position_if(b.begin(), b.end(), is_even) << endl;
cout << position_if(b.begin(), b.end(), is_odd) << endl;
cout << "-- count_if --\n";
cout << count_if(a, is_even) << endl;
cout << count_if(a, is_odd) << endl;
cout << count_if(b, is_even) << endl;
cout << count_if(b, is_odd) << endl;
cout << count_if(a.begin(), a.end(), is_even) << endl;
cout << count_if(a.begin(), a.end(), is_odd) << endl;
cout << count_if(b.begin(), b.end(), is_even) << endl;
cout << count_if(b.begin(), b.end(), is_odd) << endl;
cout << "-- mapcar --\n";
vector<int> c1 = mapcar(a, square);
print_seq(c1);
list<int> c2 = mapcar(b, square);
print_seq(c2);
vector<int> d1(a.size());
mapcar(a.begin(), a.end(), square, d1.begin());
print_seq(d1);
list<int> d2(b.size());
mapcar(b.begin(), b.end(), square, d2.begin());
print_seq(d2);
cout << "-- remove --\n";
vector<int> e1 = {1, 2, 3, 4, 5, 6, 7, 8};
auto iter1 = remove(e1.begin(), e1.end(), 5);
for (auto iter = e1.begin(); iter != iter1; ++iter)
cout << *iter << " ";
cout << endl;
auto iter2 = remove_if(e1.begin(), e1.end(), is_even);
for (auto iter = e1.begin(); iter != iter2; ++iter)
cout << *iter << " ";
cout << endl;
list<int> e2 = {1, 2, 3, 4, 5, 6, 7, 8};
auto iter3 = remove(e2.begin(), e2.end(), 5);
for (auto iter = e2.begin(); iter != iter3; ++iter)
cout << *iter << " ";
cout << endl;
auto iter4 = remove_if(e2.begin(), e2.end(), is_even);
for (auto iter = e2.begin(); iter != iter4; ++iter)
cout << *iter << " ";
cout << endl;
cout << "-- fold --\n";
cout << fold_left(a, 0, plus<int>()) << endl;
cout << fold_right(a, 0, plus<int>()) << endl;
cout << fold_left(b, 0, plus<int>()) << endl;
cout << fold_right(b, 0, plus<int>()) << endl;
cout << fold(a.begin(), a.end(), 0, plus<int>()) << endl;
cout << fold(b.begin(), b.end(), 0, plus<int>()) << endl;
cout << "-- any --\n";
cout << any(a, is_even) << endl;
cout << any(a, is_odd) << endl;
cout << any(b, is_even) << endl;
cout << any(b, is_odd) << endl;
cout << any(a.begin(), a.end(), is_even) << endl;
cout << any(a.begin(), a.end(), is_odd) << endl;
cout << any(b.begin(), b.end(), is_even) << endl;
cout << any(b.begin(), b.end(), is_odd) << endl;
cout << "-- every --\n";
cout << every(a, is_even) << endl;
cout << every(a, is_odd) << endl;
cout << every(b, is_even) << endl;
cout << every(b, is_odd) << endl;
cout << every(a.begin(), a.end(), is_even) << endl;
cout << every(a.begin(), a.end(), is_odd) << endl;
cout << every(b.begin(), b.end(), is_even) << endl;
cout << every(b.begin(), b.end(), is_odd) << endl;
cout << "-- iota --\n";
vector<int> h1(10);
iota(h1, 1);
for (int x : h1) cout << x << " ";
cout << endl;
list<int> h2(10);
iota(h2, 11);
for (int x : h2) cout << x << " ";
cout << endl;
cout << "-- tabulate --\n";
vector<int> i1(10);
tabulate(i1, 1, square);
for (int x : i1) cout << x << " ";
cout << endl;
list<int> i2(10);
tabulate(i2, 11, square);
for (int x : i2) cout << x << " ";
cout << endl;
cout << "-- substitute --\n";
vector<int> j1 = {1, 2, 3, 1, 2, 3, 1, 2, 3};
substitute(2, 4, j1);
for (int x : j1) cout << x << " ";
cout << endl;
substitute(1, 10, j1.begin(), j1.end());
for (int x : j1) cout << x << " ";
cout << endl;
list<int> j2 = {1, 2, 3, 1, 2, 3, 1, 2, 3};
substitute(2, 4, j2);
for (int x : j2) cout << x << " ";
cout << endl;
substitute(1, 10, j2.begin(), j2.end());
for (int x : j2) cout << x << " ";
cout << endl;
cout << "-- substitute_if --\n";
vector<int> k1 = {1,2,3,4,5,6,7,8};
substitute_if(is_even, 0, k1);
for (int x : k1) cout << x << " ";
cout << endl;
substitute_if(is_odd, 1, k1.begin(), k1.end());
for (int x : k1) cout << x << " ";
cout << endl;
list<int> k2 = {1,2,3,4,5,6,7,8};
substitute_if(is_even, 0, k2);
for (int x : k2) cout << x << " ";
cout << endl;
substitute_if(is_odd, 1, k2.begin(), k2.end());
for (int x : k2) cout << x << " ";
cout << endl;
cout << "-- acons --\n";
list<pair<string, int>> alist;
acons("foo", 1, alist);
acons("bar", 2, alist);
acons("baz", 3, alist);
for (auto& p : alist)
cout << p.first << "," << p.second << " ";
cout << endl;
auto aiter1 = assoc("foo", alist.begin(), alist.end());
if (aiter1 != alist.end())
cout << aiter1->second << endl;
else
cout << "not found\n";
auto aiter2 = assoc("oops", alist.begin(), alist.end());
if (aiter2 != alist.end())
cout << aiter2->second << endl;
else
cout << "not found\n";
}
$ clang++ yacp3.cpp $ ./a.out -- maximum -- 9 10 -- minimum -- 1 2 -- member -- 1 0 0 1 1 0 0 1 -- position-- 0 -1 -1 4 0 -1 -1 4 -- count -- 1 0 0 1 1 0 0 1 -- member_if -- 0 1 1 0 0 1 1 0 -- position_if -- -1 0 0 -1 -1 0 0 -1 -- count_if -- 0 5 5 0 0 5 5 0 -- mapcar -- 1 9 25 49 81 4 16 36 64 100 1 9 25 49 81 4 16 36 64 100 -- remove -- 1 2 3 4 6 7 8 1 3 7 1 2 3 4 6 7 8 1 3 7 -- fold -- 25 25 30 30 25 30 -- any -- 0 1 1 0 0 1 1 0 -- every -- 0 1 1 0 0 1 1 0 -- iota -- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -- tabulate -- 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 -- substitute -- 1 4 3 1 4 3 1 4 3 10 4 3 10 4 3 10 4 3 1 4 3 1 4 3 1 4 3 10 4 3 10 4 3 10 4 3 -- substitute_if -- 1 0 3 0 5 0 7 0 1 0 1 0 1 0 1 0 1 0 3 0 5 0 7 0 1 0 1 0 1 0 1 0 -- acons -- baz,3 bar,2 foo,1 1 not found