この節で説明するアルゴリズムはすべて、ある種の変換を行うことによって、既存のシーケンスから新規シーケンスを生成するために使用されます。一般に、出力シーケンスは出力反復子によって定義されます。つまり、これらのアルゴリズムを使用して、vector などの既存の構造体を上書きすることができます。代わりに、挿入反復子 (2.4 節を参照) を使用して、このアルゴリズムは新規要素を set や list などの可変長構造体に挿入することができます。最後に、この節で取り上げる例では、出力反復子が入力反復子によって指定されたシーケンスと同一であることもあり、その場合はインプレース変換ができます。
関数 partial_sum() および adjacent_difference() は、ヘッダーファイル numeric で宣言されますが、その他の関数はヘッダーファイル algorithm で定義されます。
注 : 以降の節で説明する関数例は、alg6.cpp ファイルにあります。
アルゴリズム transform() を使用して、単一シーケンスの一般的な変換を行ったり、2 つの異なるシーケンスの対応する要素へ 2 項関数を対ごとに適用して、新規シーケンスを生成することができます。引数と結果の型の一般定義は次のとおりです。
OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result, UnaryFunction); OutputIterator transform (InputIterator first1, InputIterator last1, InputIterator first2, OutputIterator result, BinaryFunction);
最初の書式は、シーケンスの各要素に単項関数を適用します。以下に挙げるプログラム例では、 リンクした list に値の算術否定を適用する integer 値の vector を生成するためにこの書式が使用されています。入力および出力反復子が同一のこともありますが、この場合、プログラム例に示すように変換は同じ位置で適用されます。
第 2 の書式は、2 つのシーケンスを使用して、2 項関数を対ごとに対応する要素に適用します。このトランザクションは、第 2 のシーケンスが最初のシーケンスと同じかそれ以上の要素を含むことを想定していますが、確認はされません。結果は、第 3 のシーケンスとなるか、2 つの入力シーケンスのいずれかとなります。
int square(int n) { return n * n; } void transform_example () // transform アルゴリズムの使用方法を説明する // 完全なソースコードについては alg6.cpp を参照 { // 値 1 〜 6 のリストを生成する list<int> aList; generate_n (inserter(aList, aList.begin()), 6, iotaGen(1)); // 2 乗によって要素を変換し、vector にコピーする vector<int> aVec(6); transform (aList.begin(), aList.end(), aVec.begin(), square); // vector を同じ位置で再度変換し 4 乗する transform (aVec.begin(), aVec.end(), aVec.begin(), square); // 並行変換し、立方体を生成する vector<int> cubes(6); transform (aVec.begin(), aVec.end(), aList.begin(), cubes.begin(), divides<int>()); }
シーケンスの部分和は、先行するすべての要素の値を加算することによって各要素が形成される新規シーケンスです。たとえば、ベクトル 1 3 2 4 5 の部分和は、新規ベクトル 1 4 6 10 15 となります。要素 4 は、和 1 + 3 から形成され、また、要素 6 は和 1 + 3 + 2 から形成されます (以下同様に続きます)。演算の説明に和という用語が使用されていますが、この 2 項関数は任意の関数です。プログラム例では、これを部分積の計算を使用して説明します。
部分和関数の引数は、次のように定義されます。
OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result [, BinaryFunction] );
入力反復子と結果に同じ値を使用することで、部分和をインプレース変換に変更することができます。
void partial_sum_example () // 部分和アルゴリズムの使用方法を説明する // 完全なソースコードについては alg6.cpp を参照 { // 1 〜 5 の値を生成する vector<int> aVec(5); generate (aVec.begin(), aVec.end(), iotaGen(1)); // 部分和を出力する partial_sum (aVec.begin(), aVec.end(), ostream_iterator<int> (cout, " ")), cout << endl; // 部分積を出力する partial_sum (aVec.begin(), aVec.end(), ostream_iterator<int> (cout, " "), times<int>() ); }
シーケンスの隣接差とは、各要素を要素とその直前の要素の差で置換して形成される新規シーケンスです。新規シーケンスの最初の値は未変更のままです。たとえば、(1, 3, 2, 4, 5) のようなシーケンスは (1, 3-1, 2-3, 4-2, 5-4)に変換され、その結果シーケンス (1, 2, -1, 2, 1) となります。
アルゴリズム partial_sum() と同様に、差という用語は任意の 2 項関数と置き換えられるので、必ずしも正確ではありません。たとえば、このシーケンスの隣接和は (1, 4, 5, 6, 9) となります。隣接差アルゴリズムは、次のように宣言されます。
OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result [, BinaryFunction ]);
入力および出力反復子に同一の反復子を使用すると、同じ位置で隣接差演算を実行することができます。
void adjacent_difference_example () // 隣接差アルゴリズムの使用方法を説明する // 完全なソースコードについては alg6.cpp を参照 { // 値 1 〜 5 を生成する vector<int> aVec(5); generate (aVec.begin(), aVec.end(), iotaGen(1)); // 隣接差を出力する adjacent_difference (aVec.begin(), aVec.end(), ostream_iterator<int,char> (cout, " ")), cout << endl; // 隣接和を出力する adjacent_difference (aVec.begin(), aVec.end(), ostream_iterator<int,char> (cout, " "), plus<int>() ); }