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;
}
コメント