範囲の要素を変更する関数の説明です。
概要
配列やコンテナの要素の変更を行えます。
範囲はシーケンシャルアクセスが必要です。
範囲の指定方法は、
・std::xxx(C++03): 対象の範囲 [first, last) のイテレータ―を指定します。
・std::ranges::xxx(C++20): 対象の範囲 [first, last) のイテレータ―を指定します。
・std::ranges::xxx(C++20): 対象の範囲を直接指定します。
条件判定や、値生成に関数を指定するものがあります。(後述)
std::ranges::xxx(C++20): 射影(projection)関数を指定できるものがあります。(後述)
出力先は、既存の範囲に上書きするものと、別途出力先のイテレーターを指定するものがあります。(後述)
詳細についてはこちらを参照してください。https://mappuri.com/program/cpp20-algorithm/
要素を指定した値で生成
generate
要素を指定した値で生成します。
値を生成する関数を指定します。
generate_n
先頭の指定数の要素を指定した値で生成します。
値を生成する関数を指定します。
出力先のイテレーターを指定します。
generate, generate_n のサンプル (C++03)
#include <algorithm>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
{
// 要素を指定した値で生成します。(C++03)
std::vector<int> r(5);
int n = 1;
std::generate(r.begin(), r.end(), [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// 先頭の指定数の要素を指定した値で生成します。(C++03)
// インクリメント可能なイテレーター
std::vector<int> r(5);
int n = 1;
std::generate_n(r.begin(), 3, [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 0, 0
}
return 0;
}
generate, generate_n のサンプル (C++20 range, iterater)
#include <algorithm>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
{
// 要素を指定した値で生成します。(C++20)
std::vector<int> r(5);
int n = 1;
std::ranges::generate(r, [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// 先頭の指定数の要素を指定した値で生成します。(C++20)
// インクリメント可能なイテレーター
std::vector<int> r(5);
int n = 1;
std::ranges::generate_n(r.begin(), 3, [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 0, 0
}
return 0;
}
要素を指定した値で埋める
fill
要素を指定した値で埋めます。
埋めるを指定します。
fill_n
先頭の指定数の要素を指定した値で埋めます。
埋めるを指定します。
出力先のイテレーターを指定します。
fill, fill_n のサンプル (C++03)
#include <algorithm>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
{
// 要素を指定した値で埋めます。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::fill(r.begin(), r.end(), 10);
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:10, 10, 10, 10, 10
}
{
// 先頭の指定数の要素を指定した値で埋めます。(C++03)
// インクリメント可能なイテレーター
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::fill_n(r.begin(), 3, 20);
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:20, 20, 20, 4, 5
}
return 0;
}
fill, fill_n のサンプル (C++20 range, iterater)
#include <algorithm>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
{
// 要素を指定した値で埋めます。(C++20)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::ranges::fill(r, 10);
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:10, 10, 10, 10, 10
}
{
// 先頭の指定数の要素を指定した値で埋めます。(C++20)
// インクリメント可能なイテレーター
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::ranges::fill_n(r.begin(), 3, 20);
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:20, 20, 20, 4, 5
}
return 0;
}
要素を変換
transform
1つまたは2つの範囲の要素を変換して出力します。
入出力の範囲の型は一致している必要はありません。
出力先のイテレーターを指定します。
値を生成する関数を指定します。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
transform のサンプル (C++03)
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char* argv[]) {
{
// 要素を変換して出力します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<int> o(r.size());
auto transform = std::transform(r.begin(), r.end(), o.begin(), [](int x) { return x * x; }); // 2乗
output(o, o.begin(), transform); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// 要素を変換して出力します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<int> r2 = { 10, 20, 30, 40, 50 };
std::vector<std::string> o(r.size());
auto transform = std::transform(r.begin(), r.end(), r2.begin(), o.begin(),
[](int x, int y) { return "(" + std::to_string(x) + "," + std::to_string(y) + ")"; }); // 文字列化
output(o, o.begin(), transform); // 範囲:[0, 5) 値:(1,10), (2,20), (3,30), (4,40), (5,50)
}
return 0;
}
transform のサンプル (C++20, range)
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char* argv[]) {
{
// 要素を変換して出力します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<int> o(r.size());
auto transform = std::ranges::transform(r, o.begin(), [](int x) { return x * x; }); // 2乗
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// 要素を変換して出力します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<int> r2 = { 10, 20, 30, 40, 50 };
std::vector<std::string> o(r.size());
auto transform = std::ranges::transform(r, r2, o.begin(),
[](int x, int y) { return "(" + std::to_string(x) + "," + std::to_string(y) + ")"; }); // 文字列化
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:(1,10), (2,20), (3,30), (4,40), (5,50)
}
return 0;
}
要素を置換
replace
指定した値の要素を指定した値に置換します。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
replace_if
指定した条件の要素を指定した値に置換します。
条件として関数で true を返した要素が置換対象になります。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
replace_copy
指定した値の要素を指定した値に置換します。
出力先のイテレーターを指定します。入出力の範囲の型は一致している必要はありません。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
replace_copy_if
指定した値の要素を指定した値に置換します。
出力先のイテレーターを指定します。入出力の範囲の型は一致している必要はありません。
条件として関数で true を返した要素が置換対象になります。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
replace, … のサンプル (C++03)
#include <algorithm>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
{
// 指定した値の要素を指定した値に置換します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::replace(r.begin(), r.end(), 3, 0);
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 2, 0, 4, 5
}
{
// 指定した条件の要素を指定した値に置換します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::replace_if(r.begin(), r.end(), [](int x) { return x & 1; }, 0); // 奇数を置換
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:0, 2, 0, 4, 0
}
{
// 指定した値の要素を指定した値に置換します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<int> o(r.size());
auto replace_copy = std::replace_copy(r.begin(), r.end(), o.begin(), 3, 0);
output(o, o.begin(), replace_copy); // 範囲:[0, 5) 値:1, 2, 0, 4, 5
}
{
// 指定した条件の要素を指定した値に置換します。(C++03)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<double> o(r.size());
auto replace_copy_if = std::replace_copy_if(
r.begin(), r.end(), o.begin(), [](int x) { return x & 1; }, 0.0); // 奇数を置換
output(o, o.begin(), replace_copy_if); // 範囲:[0, 5) 値:0, 2, 0, 4, 0
}
return 0;
}
replace, … のサンプル (C++20, range)
#include <algorithm>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
{
// 指定した値の要素を指定した値に置換します。(C++20)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::ranges::replace(r, 3, 0);
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 2, 0, 4, 5
}
{
// 指定した条件の要素を指定した値に置換します。(C++20)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::ranges::replace_if(r, [](int x) { return x & 1; }, 0); // 奇数を置換
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:0, 2, 0, 4, 0
}
{
// 指定した値の要素を指定した値に置換します。(C++20)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<int> o(r.size());
auto replace_copy = std::ranges::replace_copy(r, o.begin(), 3, 0);
output(o, o.begin(), replace_copy.out); // 範囲:[0, 5) 値:1, 2, 0, 4, 5
}
{
// 指定した条件の要素を指定した値に置換します。(C++20)
std::vector<int> r = { 1, 2, 3, 4, 5 };
std::vector<double> o(r.size());
auto replace_copy_if = std::ranges::replace_copy_if(
r, o.begin(), [](int x) { return x & 1; }, 0.0); // 奇数を置換
output(o, o.begin(), replace_copy_if.out); // 範囲:[0, 5) 値:0, 2, 0, 4, 0
}
return 0;
}
条件判定・値生成関数
条件判定や、値生成に関数を指定するものがあります。
#include <algorithm>
#include <iostream>
#include <vector>
int n = 1;
int func() {
int res = n * n; ++n; return res;
}
int main(int argc, char* argv[]) {
// 要素を指定した値で生成します。(C++03)
{
// ラムダ関数(キャプチャー使用)
std::vector<int> r = { 1, 2, 3, 4, 5 };
int n = 1;
std::generate(r.begin(), r.end(), [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// ラムダ関数変数
std::vector<int> r = { 1, 2, 3, 4, 5 };
int n = 1;
auto f = [&n]() { int res = n * n; ++n; return res; };
std::generate(r.begin(), r.end(), f); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// 関数
std::vector<int> r = { 1, 2, 3, 4, 5 };
n = 1;
std::generate(r.begin(), r.end(), func); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 16, 25
}
{
// 組み込み関数
const char* r[] = { "111", "22", "3", "077", "0xff" };
int o[std::size(r)];
std::transform(r, std::end(r), o, atoi); // 数値に変換
output(o, o, std::end(o)); // 範囲:[0, 5) 値:111, 22, 3, 77, 0
}
return 0;
}
射影(projection)関数
条件判定・値生成関数が受け取る型を変更する場合に指定します。(C++20)
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct S1 {
const char* str;
};
int proj(const S1& s1) {
return std::stoi(s1.str, nullptr, 0);
}
int main(int argc, char* argv[]) {
std::vector<S1> r = { {"111"}, {"22"}, {"3"}, {"077"}, {"0xff"} };
auto f = [](int x) { return x * x; }; // 2乗
std::vector<int> o(r.size());
{
// ラムダ関数
auto transform = std::ranges::transform(r, o.begin(), f, [](const auto& s1) { return std::stoi(s1.str, nullptr, 0); });
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:12321, 484, 9, 3969, 65025
}
{
// ラムダ関数変数
auto p = [](auto& s1) { return std::stoi(s1.str, nullptr, 0); };
auto transform = std::ranges::transform(r, o.begin(), f, p);
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:12321, 484, 9, 3969, 65025
}
{
// 関数
auto transform = std::ranges::transform(r, o.begin(), f, proj);
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:12321, 484, 9, 3969, 65025
}
{
// 組み込み関数
const char* r2[] = { "111", "22", "3", "077", "0xff" };
auto transform = std::ranges::transform(r2, o.begin(), f, atoi);
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:12321, 484, 9, 5929, 0
}
{
// メンバー変数ポインター
auto f = [](const char* str) { int x = std::stoi(str, nullptr, 0); return x * x; }; // 2乗
auto transform = std::ranges::transform(r, o.begin(), f, &S1::str);
output(o, o.begin(), transform.out); // 範囲:[0, 5) 値:12321, 484, 9, 3969, 65025
}
return 0;
}
出力先のイテレーター
出力先のイテレーターとして以下のものが指定できます。
・インクリメント可能なイテレーター
r.begin() やポインタなどです。指定位置以降に要素が上書きされます。容量をあらかじめ確保しておく必要があります。
・back_insert_iterator
範囲の末尾に要素が追加されます。
・insert_iterator
指定位置以降に要素が挿入されます。
・ostream_iterator
コンソールやファイルなどに出力します。
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
int main(int argc, char* argv[]) {
// 先頭の指定数の要素を指定した値で生成します。(C++03)
{
// インクリメント可能なイテレーター
std::vector<int> r = { 1, 2, 3, 4, 5 };
int n = 1;
std::generate_n(r.begin(), 3, [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 4, 9, 0, 0
}
{
// back_insert_iterator
std::list<int> o_back_insert = { 0, 0, 0, 0, 0 };
int n = 1;
std::generate_n(std::back_inserter(o_back_insert), 3, [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(o_back_insert, o_back_insert.begin(), o_back_insert.end()); // 範囲:[0, 8) 値:0, 0, 0, 0, 0, 1, 4, 9
}
{
// insert_iterator
std::list<int> o_insert = { 0, 0, 0, 0, 0 };
int n = 1;
std::generate_n(std::inserter(o_insert, std::next(o_insert.begin(), 3)), 3, [&n]() { int res = n * n; ++n; return res; }); // 2乗
output(o_insert, o_insert.begin(), o_insert.end()); // 範囲:[0, 8) 値:0, 0, 0, 1, 4, 9, 0, 0
}
{
// ostream_iterator
int n = 1;
std::generate_n(std::ostream_iterator<int>(std::cout, ","), 3, [&n]() { int res = n * n; ++n; return res; }); // 2乗
// 1,4,9,
}
return 0;
}
コメント