範囲の要素の変更 (C++03, C++20)

C++

範囲の要素を変更する関数の説明です。

概要

配列やコンテナの要素の変更を行えます。
範囲はシーケンシャルアクセスが必要です。
範囲の指定方法は、
・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;
}

コメント

タイトルとURLをコピーしました