C++汎用アルゴリズム:変換と要素の結合

transform()

C++標準ライブラリにおけるstd::transformは、指定された範囲内の各要素に対して特定の操作を実行し、その結果を別のコンテナに格納する汎用アルゴリズムです。このアルゴリズムは、要件を満たす任意の関数オブジェクトやラムダ式を使用して操作を定義できるため、非常に柔軟性があります。

以下はstd::transformの基本的な使用例で、std::vector内の各要素を3倍にするものです:

#include <iostream>
#include <vector>
#include <algorithm> // std::transform用
#include <iterator>  // std::begin, std::end用

int main() {
   // 整数を含むベクトルを作成
   std::vector<int> nums = {10, 20, 30, 40, 50};

   // 変換結果を格納する新しいベクトルを作成
   std::vector<int> tripled_nums(nums.size());

   // std::transformを使用してnumsの各要素を3倍し、結果をtripled_numsに格納
   std::transform(std::begin(nums), std::end(nums), std::begin(tripled_nums),
                  [](int val) { return val * 3; });

   // 変換結果を出力
   for (const auto& item : tripled_nums) {
       std::cout << item << " ";
   }

   return 0;
}

この例では、各要素を3倍する操作を定義するためにラムダ式[](int val) { return val * 3; }を使用しています。std::transformアルゴリズムはnumsベクトルの各要素を走査し、ラムダ式を適用してその結果をtripled_numsベクトルに格納します。

std::transformは、文字列内の小文字を大文字に変換するなど、より複雑な操作にも使用できます:

#include <iostream>
#include <string>
#include <algorithm> // std::transform用
#include <cctype>    // std::toupper用

int main() {
   // 小文字を含む文字列を作成
   std::string input_text = "c++ programming is powerful";

   // std::transformを使用して小文字を大文字に変換
   std::transform(std::begin(input_text), std::end(input_text),
                  std::begin(input_text),
                  [](unsigned char c){ return std::toupper(c); });

   // 変換結果を出力
   std::cout << input_text << std::endl;

   return 0;
}

この例では、小文字を大文字に変換する操作を定義するためにstd::toupper関数を使用しています。入力範囲と出力範囲として同じイテレータを提供しているため、std::transformアルゴリズムはinput_textの要素を直接変更します。

要するに、std::transformはコンテナ内の要素に対してカスタム操作を実行し、その結果を別のコンテナに格納できる強力な汎用アルゴリズムです。

C++標準ライブラリのstd::transformアルゴリズムには、二項演算を取るバージョン(binary operation version)も存在します。このバージョンは2つの入力範囲を受け取り、これらの範囲内の対応する要素に対して二項演算を適用し、その結果を出力イテレータが指す位置に格納します。このバージョンのstd::transformは通常、2つのシーケンスの要素を組み合わせたり、新しいシーケンスに変換したりするために使用されます。

以下はstd::transformの二項演算バージョンの例で、2つのstd::vectorの対応する要素を掛け合わせ、その結果を3つ目のstd::vectorに格納します:

#include <iostream>
#include <vector>
#include <algorithm> // std::transform用
#include <iterator>  // std::begin, std::end用

int main() {
   // 2つの整数ベクトルを作成
   std::vector<int> data1 = {2, 4, 6, 8, 10};
   std::vector<int> data2 = {1, 3, 5, 7, 9};

   // 変換結果を格納する新しいベクトルを作成
   std::vector<int> products(data1.size());

   // std::transformを使用して2つのベクトルの対応する要素を掛け合わせ、結果をproductsに格納
   std::transform(std::begin(data1), std::end(data1),
                  std::begin(data2), std::begin(products),
                  std::multiplies<int>()); // 二項演算としてstd::multipliesを使用

   // 変換結果を出力
   for (const auto& result : products) {
       std::cout << result << " ";
   }

   return 0;
}

この例では、std::multiplies()は乗算を定義する関数オブジェクトです。std::transformはdata1とdata2の各対応する要素を走査し、それらを掛け合わせ、その結果をproductsに格納します。

ラムダ式を二項演算として使用することもでき、これによりコードはより簡潔で柔軟になります。以下はラムダ式を使用した同じ例です:

#include <iostream>
#include <vector>
#include <algorithm> // std::transform用
#include <iterator>  // std::begin, std::end用

int main() {
   // 2つの整数ベクトルを作成
   std::vector<int> vec1 = {2, 4, 6, 8, 10};
   std::vector<int> vec2 = {1, 3, 5, 7, 9};

   // 変換結果を格納する新しいベクトルを作成
   std::vector<int> results(vec1.size());

   // ラムダ式を二項演算として使用
   std::transform(std::begin(vec1), std::end(vec1),
                  std::begin(vec2), std::begin(results),
                  [](int x, int y) { return x * y; });

   // 変換結果を出力
   for (const auto& item : results) {
       std::cout << item << " ";
   }

   return 0;
}

このラムダ式を使用した例では、二項演算を2つの整数の乗算として直接定義しています。これはstd::multiplies()を使用する場合と同じ効果を持ちます。ラムダ式は、特に演算が比較的複雑である場合や、コンテキストに応じてカスタマイズする必要がある場合により簡潔で柔軟な方法を提供します。

タグ: C++ 汎用アルゴリズム transform ラムダ式 イテレータ

6月8日 21:08 投稿