範囲の繰り返し処理 while, do-while, for, for_each, for_each_n (C/C++)

C++

C/C++ で配列や STL コンテナの各要素に繰り返し処理を行う方法のまとめです。

while, do-while, for 文

配列やコンテナの繰り返し処理を行えます。
要素はシーケンシャルアクセスが必要です。インデックス参照する場合はランダムアクセスが必要です。
かっこ内に指定した条件が成り立つ間繰り返します。
範囲 for 文は範囲を直接指定します。(C++11)

#include <iostream>

/** r 内の [first, last) の範囲と値を出力 範囲:[0, 9) 値:1 2 3 4 5 4 5 6 6 */
template<class T, class U, class V>
static void output(T&& r, U&& first, V&& last) {
	std::cout << "範囲:[" << std::distance(std::begin(r), first) << ", " << std::distance(std::begin(r), last) << ")";
	std::cout << " 値:";
	for (auto i = first; i != last; ++i) {
		std::cout << *i << " ";
	}
	std::cout << std::endl;
}

/** r 内の it の位置と値を出力 位置:2 値:3 */
template<class T, class U>
static void output(T&& r, U&& it) {
	std::cout << "位置:" << std::distance(std::begin(r), it);
	std::cout << " 値:";
	if (it == std::end(r) || &*it == nullptr) {
		std::cout << "end";
	} else {
		std::cout << *it;
	}
	std::cout << std::endl;
}

#include <iostream>
#include <vector>

int main(int argc, char* argv[]) {
	std::vector<int> r = { 1, 2, 3, 4, 5 };

	// while インデックス使用
	size_t i1 = 0;
	while (i1 < r.size()) {
		std::cout << r[i1] << ' ';
		++i1;
	}
	std::cout << std::endl;
	// 1 2 3 4 5

	// do-while インデックス使用
	if (r.size() >= 1) {
		size_t i2 = 0;
		do {
			std::cout << r[i2] << ' ';
			++i2;
		} while (i2 < r.size());
	}
	std::cout << std::endl;
	// 1 2 3 4 5

	// for インデックス使用
	for (size_t i = 0; i < r.size(); ++i) {
		std::cout << r[i] << ' ';
	}
	std::cout << std::endl;
	// 1 2 3 4 5

	// for イテレーター使用
	for (auto i = r.begin(); i != r.end(); ++i) {
		std::cout << *i << ' ';
	}
	std::cout << std::endl;
	// 1 2 3 4 5

	// for 範囲使用 (C++11)
	for (auto x : r) {
		std::cout << x << ' ';
	}
	std::cout << std::endl;
	// 1 2 3 4 5

	return 0;
}

STL for_each, for_each_n

配列やコンテナの繰り返し処理を行えます。
範囲はシーケンシャルアクセスが必要です。
範囲の指定方法は、
・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/

for_each

範囲の要素を繰り返し処理します。

for_each_n

範囲の先頭の指定数の要素を繰り返し処理します。

#include <algorithm>
#include <iostream>
#include <list>
#include <vector>

int main(int argc, char* argv[]) {
	std::vector<int> r = { 1, 2, 3, 4, 5 };
	int a[] = { 1, 2, 3, 4, 5 };
	std::list<int> l = { 1, 2, 3, 4, 5 };

	// 範囲の要素を繰り返し処理します。 (C++03)
	auto for_each = std::for_each(r.begin(), r.end(), [](int x) { std::cout << x << ' '; });
	std::cout << std::endl;
	// 1 2 3 4 5

	// 範囲の先頭の指定数の要素を繰り返し処理します。 (C++17)
	auto for_each_n = std::for_each_n(r.begin(), 3, [](int x) { std::cout << x << ' '; });
	std::cout << std::endl;
	output(r, for_each_n);
	// 1 2 3
	// 位置:3 値:4

	// 範囲の要素を繰り返し処理します。 (C++20 iterator)
	auto for_each_20iterator = std::ranges::for_each(r.begin(), r.end(), [](int x) { std::cout << x << ' '; });
	std::cout << std::endl;
	output(r, for_each_20iterator.in);
	// 1 2 3 4 5
	// 位置:5 値:end

	// 範囲の要素を繰り返し処理します。 (C++20 range)
	auto for_each_20range = std::ranges::for_each(r, [](int x) { std::cout << x << ' '; });
	std::cout << std::endl;
	output(r, for_each_20range.in);
	// 1 2 3 4 5
	// 位置:5 値:end

	// 配列
	std::for_each(a, a + 5, [](int x) { std::cout << x << ' '; });
	std::for_each(std::begin(a), std::end(a), [](int x) { std::cout << x << ' '; });
	std::ranges::for_each(a, [](int x) { std::cout << x << ' '; });
	// 1 2 3 4 5

	// list(シーケンシャルアクセス可能なコンテナ)
	std::for_each(l.begin(), l.end(), [](int x) { std::cout << x << ' '; });
	std::for_each(std::begin(l), std::end(l), [](int x) { std::cout << x << ' '; });
	std::ranges::for_each(l, [](int x) { std::cout << x << ' '; });
	// 1 2 3 4 5

	// イテレーター・view を使うことで特定の範囲を渡すことができます。
	auto found = std::find(l.begin(), l.end(), 3);
	std::for_each(l.begin(), found, [](int x) { std::cout << x << ' '; });
	std::ranges::for_each(std::ranges::subrange(l.begin(), found), [](int x) { std::cout << x << ' '; });
	// 1 2

	return 0;
}

処理関数

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <math.h>

struct S1 {
	const char* str;
};

void func(const S1& s1) {
	std::cout << s1.str << " ";
}

int main(int argc, char* argv[]) {
	std::vector<S1> r = { {"111"}, {"22"}, {"3"}, {"077"}, {"0xff"} };

	// ラムダ関数
	std::ranges::for_each(r, [](auto& s1) { std::cout << s1.str << " "; });
	std::cout << std::endl;
	// 111 22 3 077 0xff

	// ラムダ関数(キャプチャー使用)
	int sqr_sum = 0;
	std::ranges::for_each(r, [&sqr_sum](auto& s1) { int i = std::stoi(s1.str, nullptr, 0); sqr_sum += i * i; });
	std::cout << sqr_sum << std::endl;
	// 81808

	// ラムダ関数変数
	auto f = [](auto& s1) { std::cout << s1.str << " "; };
	std::ranges::for_each(r, f);
	std::cout << std::endl;
	// 111 22 3 077 0xff

	// 関数
	std::ranges::for_each(r, func);
	std::cout << std::endl;
	// 111 22 3 077 0xff

	// 組み込み関数
	std::ranges::for_each(r, printf, &S1::str);
	std::cout << std::endl;
	// 1112230770xff

	return 0;
}

射影(projection)関数

処理関数が受け取る型を変更する場合に指定します。

#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 = [](const auto& x) { std::cout << x << " "; };

	// ラムダ関数
	std::ranges::for_each(r, f, [](const auto& s1) { return std::stoi(s1.str, nullptr, 0); });
	std::cout << std::endl;
	// 111 22 3 63 255

	// ラムダ関数変数
	auto p = [](auto& s1) { return std::stoi(s1.str, nullptr, 0); };
	std::ranges::for_each(r, f, p);
	std::cout << std::endl;
	// 111 22 3 63 255

	// 関数
	std::ranges::for_each(r, f, proj);
	std::cout << std::endl;
	// 111 22 3 63 255

	// 組み込み関数
	const char* r2[] = { "111", "22", "3", "077", "0xff" };
	std::ranges::for_each(r2, f, atoi);
	std::cout << std::endl;
	// 111 22 3 77 0

	// メンバー変数ポインター
	std::ranges::for_each(r, f, &S1::str);
	std::cout << std::endl;
	// 111 22 3 077 0xff

	return 0;
}

コメント

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