繰り返し処理

[C++] std::vectorをfor文で反復処理する方法

C++のstd::vectorfor文で反復処理する方法は、インデックスを使用する方法とイテレータを使用する方法の2つがあります。

インデックスを使う場合はfor (size_t i = 0; i < vec.size(); ++i)の形式で、vec[i]で要素にアクセスします。

一方、イテレータを使う場合はfor (auto it = vec.begin(); it != vec.end(); ++it)の形式で、*itで要素を参照します。

C++11以降では範囲ベースfor文も利用可能で、for (auto& elem : vec)の形式で簡潔に記述できます。

std::vectorとは

std::vectorは、C++の標準ライブラリに含まれる動的配列の一種です。

配列のサイズを動的に変更できるため、要素の追加や削除が容易です。

以下に、std::vectorの主な特徴を示します。

特徴説明
動的サイズ要素数に応じて自動的にサイズが変更される
ランダムアクセスインデックスを使用して要素にアクセス可能
メモリ管理自動的にメモリを管理し、不要になったメモリを解放
STLとの互換性他のSTLコンテナやアルゴリズムと連携可能

std::vectorは、特に要素数が不明な場合や、頻繁に要素の追加・削除が行われる場合に非常に便利です。

次のセクションでは、std::vectorを使用したfor文での反復処理について詳しく解説します。

for文を使った反復処理の基本

std::vectorの要素を反復処理するためには、通常のfor文を使用することができます。

基本的な構文は以下の通りです。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5}; // 整数のベクターを初期化
    // for文を使って反復処理
    for (size_t i = 0; i < numbers.size(); i++) { // ベクターのサイズ分ループ
        std::cout << numbers[i] << std::endl; // 各要素を出力
    }
    return 0;
}
1
2
3
4
5

このコードでは、std::vector<int>型のnumbersというベクターを作成し、1から5までの整数を格納しています。

for文を使用して、インデックスiを使って各要素にアクセスし、出力しています。

numbers.size()でベクターのサイズを取得し、ループの条件として使用しています。

これにより、すべての要素を順番に処理することができます。

インデックスを使用した反復処理

std::vectorの要素にアクセスする際、インデックスを使用する方法は非常に一般的です。

インデックスを使うことで、特定の位置にある要素を直接参照することができます。

以下に、インデックスを使用した反復処理の例を示します。

#include <iostream>
#include <vector>
int main() {
    std::vector<std::string> fruits = {"りんご", "バナナ", "オレンジ", "ぶどう", "いちご"}; // 文字列のベクターを初期化
    // インデックスを使用して反復処理
    for (size_t i = 0; i < fruits.size(); i++) { // ベクターのサイズ分ループ
        std::cout << "フルーツ " << (i + 1) << ": " << fruits[i] << std::endl; // 各要素を出力
    }
    return 0;
}
フルーツ 1: りんご
フルーツ 2: バナナ
フルーツ 3: オレンジ
フルーツ 4: ぶどう
フルーツ 5: いちご

このコードでは、std::vector<std::string>型のfruitsというベクターを作成し、いくつかのフルーツ名を格納しています。

for文を使用して、インデックスiを使って各要素にアクセスし、出力しています。

インデックスを使うことで、要素の位置を明示的に示すことができ、特定の要素に対する操作が容易になります。

イテレータを使用した反復処理

std::vectorでは、イテレータを使用して要素を反復処理することもできます。

イテレータは、コンテナ内の要素を指し示すオブジェクトで、ポインタのように振る舞います。

イテレータを使うことで、より柔軟で安全な反復処理が可能になります。

以下に、イテレータを使用した反復処理の例を示します。

#include <iostream>
#include <vector>
int main() {
    std::vector<double> temperatures = {36.5, 37.0, 38.2, 36.8, 37.5}; // 温度のベクターを初期化
    // イテレータを使用して反復処理
    for (std::vector<double>::iterator it = temperatures.begin(); it != temperatures.end(); ++it) { // ベクターの先頭から末尾までループ
        std::cout << "温度: " << *it << " °C" << std::endl; // 各要素を出力
    }
    return 0;
}
温度: 36.5 °C
温度: 37.0 °C
温度: 38.2 °C
温度: 36.8 °C
温度: 37.5 °C

このコードでは、std::vector<double>型のtemperaturesというベクターを作成し、いくつかの温度値を格納しています。

イテレータitを使用して、temperatures.begin()からtemperatures.end()までループし、各要素にアクセスしています。

*itを使って、イテレータが指し示す要素の値を取得し、出力しています。

イテレータを使用することで、コンテナの種類に依存せずに同様の操作が可能になるため、コードの再利用性が向上します。

範囲ベースfor文を使用した反復処理

C++11以降、範囲ベースfor文を使用することで、std::vectorの要素を簡潔に反復処理することができます。

この構文は、イテレータを明示的に使用することなく、コンテナ内のすべての要素にアクセスできるため、コードがより読みやすくなります。

以下に、範囲ベースfor文を使用した反復処理の例を示します。

#include <iostream>
#include <vector>
int main() {
    std::vector<std::string> colors = {"赤", "青", "緑", "黄", "紫"}; // 色のベクターを初期化
    // 範囲ベースfor文を使用して反復処理
    for (const std::string& color : colors) { // 各要素を参照で取得
        std::cout << "色: " << color << std::endl; // 各要素を出力
    }
    return 0;
}
色: 赤
色: 青
色: 緑
色: 黄
色: 紫

このコードでは、std::vector<std::string>型のcolorsというベクターを作成し、いくつかの色名を格納しています。

範囲ベースfor文を使用して、colors内の各要素にアクセスし、出力しています。

const std::string& colorとすることで、要素を参照で取得し、コピーを避けることができ、効率的です。

範囲ベースfor文は、特に要素数が多い場合や、コードを簡潔に保ちたい場合に非常に便利です。

各方法の比較と選択基準

std::vectorの要素を反復処理する方法には、主に以下の4つがあります。

それぞれの方法の特徴と選択基準を比較してみましょう。

方法特徴利点欠点
インデックスを使用したfor文インデックスを使って要素にアクセスシンプルで直感的インデックスの範囲外アクセスに注意が必要
イテレータを使用したfor文イテレータを使って要素にアクセスコンテナの種類に依存せず再利用可能コードがやや冗長になることがある
範囲ベースfor文C++11以降の新しい構文簡潔で可読性が高い古いコンパイラでは使用できないことがある

選択基準

  • シンプルさ: 簡単な処理や小規模なプログラムでは、インデックスを使用したfor文が適しています。
  • 再利用性: 異なるコンテナを扱う場合や、STLアルゴリズムと組み合わせる場合は、イテレータを使用することが推奨されます。
  • 可読性: コードの可読性を重視する場合、範囲ベースfor文が最も適しています。

特に、要素数が多い場合や、複雑な処理を行う場合に有効です。

これらの方法を理解し、状況に応じて適切な方法を選択することで、効率的で可読性の高いコードを書くことができます。

応用例:std::vectorのネスト構造の反復処理

std::vectorは、他のstd::vectorを要素として持つことができるため、ネスト構造を作成することが可能です。

このような場合、二重のfor文や範囲ベースfor文を使用して、ネストされたベクターの要素を反復処理することができます。

以下に、ネスト構造のstd::vectorを反復処理する例を示します。

#include <iostream>
#include <vector>
int main() {
    // 整数のベクターのベクターを初期化
    std::vector<std::vector<int>> matrix = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    // ネストされたベクターを反復処理
    for (const std::vector<int>& row : matrix) { // 各行を参照で取得
        for (int value : row) { // 各行の要素を反復処理
            std::cout << value << " "; // 各要素を出力
        }
        std::cout << std::endl; // 行の終わりで改行
    }
    return 0;
}
1 2 3 
4 5 6 
7 8 9

このコードでは、std::vector<std::vector<int>>型のmatrixという二次元ベクターを作成し、3×3の整数行列を格納しています。

範囲ベースfor文を使用して、外側のベクター(行)を反復処理し、内側のfor文で各行の要素を反復処理しています。

これにより、ネストされた構造の要素を簡潔に出力することができます。

ネスト構造のstd::vectorを扱う際には、このような方法が非常に便利です。

まとめ

この記事では、std::vectorを使用した反復処理のさまざまな方法について解説しました。

インデックスを使用したfor文、イテレータ、範囲ベースfor文のそれぞれの特徴や利点を比較し、ネスト構造のstd::vectorの反復処理の実例も紹介しました。

これらの知識を活用して、実際のプログラミングにおいて効率的で可読性の高いコードを書くことに挑戦してみてください。

関連記事

Back to top button
目次へ