C#のループ処理完全ガイド:for、while、foreachの使い分けと実例

C#

プログラミングを学び始めると、必ず出てくるのが「ループ処理」です。

ループ処理とは、同じ作業を何度も繰り返すためのプログラムの仕組みのことです。

たとえば、次のような作業をコンピューターにお願いしたいとき、ループ処理が活躍します。

日常でループ処理が使われる例

  • 1から100までの数字を順番に表示する
  • ファイルの中身を1行ずつ読み取る
  • ゲームで敵キャラクターを画面に表示し続ける
  • Webサイトでユーザーのコメントを1つずつ表示する

もしループ処理がなかったら、同じコードを100回書かなければなりません。でも、ループ処理を使えば、わずか数行のコードで済みます。

この記事では、C#でよく使われる3つのループ処理(for、while、foreach)を、実際の例を使って詳しく説明します。

プログラミング初心者の方でも理解できるよう、簡単な例から始めて、だんだん実用的な使い方まで学んでいきます。

スポンサーリンク

ループ処理の基本的な考え方

ループ処理を理解するために、日常生活の例で考えてみましょう。

料理でのループ処理

「野菜を10個切る」という作業は、次のように分解できます。

  1. 野菜を1個取る
  2. 包丁で切る
  3. 切った野菜を皿に置く
  4. まだ野菜が残っていたら、1番に戻る
  5. すべて切り終わったら終了

プログラムのループ処理も、基本的にはこれと同じ考え方です。

プログラムでのループ処理の要素

  • 初期設定:ループを始める前の準備
  • 繰り返し処理:何度も実行したい作業
  • 条件判定:ループを続けるかどうかの判断
  • 更新処理:次の繰り返しに向けた準備

for文:回数が決まっているときの定番

for文とは

for文は、「何回繰り返すかが最初からわかっているとき」に使うループ処理です。

「1から10まで」「配列の要素数だけ」のように、繰り返し回数が明確な場面で活躍します。

基本的な書き方

for (初期化; 条件; 更新) {
    // 繰り返し実行したい処理
}

それぞれの部分の説明

  • 初期化:ループが始まる前に1回だけ実行される
  • 条件:この条件がtrueの間、ループが続く
  • 更新:繰り返しの最後に実行される

実際の例を見てみよう

例1:1から5まで数字を表示

for (int i = 1; i <= 5; i++) {
    Console.WriteLine($"{i}番目の処理です");
}

実行結果

1番目の処理です
2番目の処理です
3番目の処理です
4番目の処理です
5番目の処理です

動作の流れ

  1. int i = 1:変数iを1で初期化
  2. i <= 5:iが5以下かチェック(1 <= 5なのでtrue)
  3. 中身の処理を実行
  4. i++:iを1増やす(iは2になる)
  5. 2番目に戻って繰り返し

より実用的な例

例2:配列の中身をすべて表示

string[] fruits = { "りんご", "バナナ", "オレンジ", "ぶどう" };

for (int i = 0; i < fruits.Length; i++) {
    Console.WriteLine($"{i + 1}番目の果物は{fruits[i]}です");
}

実行結果

1番目の果物はりんごです
2番目の果物はバナナです
3番目の果物はオレンジです
4番目の果物はぶどうです

ここでのポイント

  • 配列のインデックスは0から始まるので、i = 0で初期化
  • fruits.Lengthで配列の要素数を取得
  • i < fruits.Lengthで配列の範囲内かチェック

例3:九九の計算

for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
        Console.Write($"{i} × {j} = {i * j:D2}  ");
    }
    Console.WriteLine(); // 改行
}

この例では、for文を2つ重ねて(二重ループ)、九九の表を作成しています。

for文が向いている場面

配列やリストの処理

  • 配列の要素を順番に処理したいとき
  • 特定のインデックスにアクセスしたいとき

決まった回数の繰り返し

  • 「10回処理を実行する」のような明確な回数指定
  • カウントダウンやカウントアップ

数値の範囲処理

  • 1から100までの数字を処理
  • 偶数だけ、奇数だけを処理

for文使用時の注意点

無限ループに注意

// 危険な例:iが増えないので永遠に終わらない
for (int i = 0; i < 10; /* i++を忘れた */) {
    Console.WriteLine(i);
}

配列の範囲外アクセスに注意

int[] numbers = { 1, 2, 3 };
// 危険な例:配列の要素数は3なのに、10回ループしようとしている
for (int i = 0; i < 10; i++) {
    Console.WriteLine(numbers[i]); // 4回目以降でエラー
}

while文:条件で動く柔軟なループ

while文とは

while文は、「ある条件が満たされている間、処理を繰り返す」ためのループ処理です。繰り返し回数が最初からはわからないけれど、「この条件を満たしている限り続ける」という場面で使います。

基本的な書き方

while (条件) {
    // 条件がtrueの間、繰り返し実行される処理
}

重要なポイント

  • 条件が最初からfalseだと、1回も実行されない
  • 条件がtrueである限り、ずっと繰り返される
  • ループの中で条件を変化させることが重要

実際の例を見てみよう

例1:ユーザーが正しい値を入力するまで繰り返す

int userInput = 0;
Console.WriteLine("1から10の数字を入力してください:");

while (userInput < 1 || userInput > 10) {
    string input = Console.ReadLine();
    
    if (int.TryParse(input, out userInput)) {
        if (userInput < 1 || userInput > 10) {
            Console.WriteLine("1から10の数字を入力してください:");
        }
    } else {
        Console.WriteLine("数字を入力してください:");
        userInput = 0; // 無効な入力なので条件を満たさないようにする
    }
}

Console.WriteLine($"正しい入力: {userInput}");

例2:ランダムな数が特定の値になるまで繰り返す

Random random = new Random();
int targetNumber = 7;
int randomNumber = 0;
int attempts = 0;

Console.WriteLine($"目標の数字: {targetNumber}");

while (randomNumber != targetNumber) {
    randomNumber = random.Next(1, 11); // 1から10のランダムな数
    attempts++;
    Console.WriteLine($"{attempts}回目: {randomNumber}");
}

Console.WriteLine($"{targetNumber}が出ました!{attempts}回かかりました。");

例3:リストから条件に合う要素を探す

List<string> names = new List<string> { "田中", "佐藤", "鈴木", "高橋", "伊藤" };
string targetName = "鈴木";
int index = 0;
bool found = false;

while (index < names.Count && !found) {
    if (names[index] == targetName) {
        found = true;
        Console.WriteLine($"{targetName}さんは{index + 1}番目にいます");
    } else {
        index++;
    }
}

if (!found) {
    Console.WriteLine($"{targetName}さんは見つかりませんでした");
}

while文が向いている場面

ユーザー入力の検証

  • 正しい値が入力されるまで再入力を求める
  • メニュー選択で有効な選択肢が選ばれるまで繰り返す

外部条件待ち

  • ファイルの読み込みが完了するまで待つ
  • ネットワーク通信の応答を待つ

探索処理

  • 条件に合うデータを見つけるまで探し続ける
  • ゲームでプレイヤーがゴールに到達するまで

do-while文:必ず1回は実行したいとき

while文の仲間に「do-while文」があります。これは必ず1回は処理を実行してから、条件をチェックするループです。

int userChoice;
do {
    Console.WriteLine("メニューを選択してください:");
    Console.WriteLine("1. ゲーム開始");
    Console.WriteLine("2. 設定");
    Console.WriteLine("3. 終了");
    
    string input = Console.ReadLine();
    int.TryParse(input, out userChoice);
    
    if (userChoice < 1 || userChoice > 3) {
        Console.WriteLine("1、2、3のいずれかを選択してください。");
    }
} while (userChoice < 1 || userChoice > 3);

Console.WriteLine($"選択されたメニュー: {userChoice}");

while文使用時の注意点

無限ループの回避

// 危険な例:条件が変わらないので永遠に終わらない
int count = 0;
while (count < 10) {
    Console.WriteLine("処理中...");
    // count++; を忘れると無限ループ
}

条件の更新を忘れない while文では、ループの中で必ず条件に関わる変数を更新する必要があります。

foreach文:コレクション処理のエキスパート

foreach文とは

foreach文は、配列やリストなどのコレクション(データの集まり)の要素を、ひとつずつ順番に処理するためのループです。

インデックスを気にせずに、データそのものに直接アクセスできるのが特徴です。

基本的な書き方

foreach (データ型 変数名 in コレクション) {
    // 各要素に対する処理
}

ポイント

  • 変数名には、コレクションの各要素が順番に入る
  • インデックス(添え字)を管理する必要がない
  • コレクションの最初から最後まで自動的に処理される

実際の例を見てみよう

例1:配列の要素をすべて表示

string[] colors = { "赤", "青", "緑", "黄色", "紫" };

foreach (string color in colors) {
    Console.WriteLine($"色: {color}");
}

実行結果

色: 赤
色: 青
色: 緑
色: 黄色
色: 紫

例2:リストの数値を合計する

List<int> scores = new List<int> { 85, 92, 78, 96, 88 };
int total = 0;

foreach (int score in scores) {
    total += score;
    Console.WriteLine($"現在のスコア: {score}, 累計: {total}");
}

double average = (double)total / scores.Count;
Console.WriteLine($"平均点: {average:F1}");

例3:辞書(Dictionary)の処理

Dictionary<string, int> studentAges = new Dictionary<string, int> {
    { "田中", 20 },
    { "佐藤", 22 },
    { "鈴木", 19 },
    { "高橋", 21 }
};

foreach (KeyValuePair<string, int> student in studentAges) {
    Console.WriteLine($"{student.Key}さんは{student.Value}歳です");
}

// より簡潔な書き方(C# 7.0以降)
foreach (var (name, age) in studentAges) {
    Console.WriteLine($"{name}さんは{age}歳です");
}

例4:文字列の各文字を処理

string message = "こんにちは";

foreach (char character in message) {
    Console.WriteLine($"文字: {character}");
}

foreach文が向いている場面

データの一覧表示

  • 商品リストの表示
  • ユーザー一覧の表示
  • ファイルの内容を行ごとに表示

集計処理

  • 合計、平均、最大値、最小値の計算
  • 条件に合うデータの個数を数える

データの検索

  • 特定の条件に合う要素を探す
  • データの存在確認

データの変換

  • 各要素に同じ処理を適用
  • フィルタリング(条件に合うものだけ抽出)

より高度なforeach文の使い方

例5:LINQ(リンク)との組み合わせ

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// 偶数だけを取り出してforeach
foreach (int evenNumber in numbers.Where(n => n % 2 == 0)) {
    Console.WriteLine($"偶数: {evenNumber}");
}

// 3倍にした値をforeach
foreach (int tripled in numbers.Select(n => n * 3)) {
    Console.WriteLine($"3倍: {tripled}");
}

例6:複雑なオブジェクトの処理

// 商品クラスの定義
public class Product {
    public string Name { get; set; }
    public int Price { get; set; }
    public string Category { get; set; }
}

// 商品リストの作成
List<Product> products = new List<Product> {
    new Product { Name = "ノートパソコン", Price = 89800, Category = "電子機器" },
    new Product { Name = "コーヒーメーカー", Price = 12800, Category = "家電" },
    new Product { Name = "プログラミング本", Price = 3200, Category = "書籍" }
};

// 商品情報の表示
foreach (Product product in products) {
    Console.WriteLine($"商品名: {product.Name}");
    Console.WriteLine($"価格: {product.Price:C0}");
    Console.WriteLine($"カテゴリ: {product.Category}");
    Console.WriteLine("---");
}

foreach文使用時の注意点

読み取り専用 foreach文では、ループ中に要素の値を変更することはできません。

List<int> numbers = new List<int> { 1, 2, 3 };

foreach (int number in numbers) {
    // number = number * 2; // エラー:値を変更できない
    Console.WriteLine(number * 2); // 表示だけならOK
}

コレクションの変更は危険 foreach文の実行中に、元のコレクション(配列やリスト)の要素を追加・削除すると、エラーが発生することがあります。

List<string> items = new List<string> { "A", "B", "C" };

// 危険な例
foreach (string item in items) {
    if (item == "B") {
        items.Remove(item); // エラーの可能性
    }
}

3つのループの使い分けガイド

どのループを使えばよいか迷ったときの判断基準をまとめました。

for文を選ぶべき場面

✅ こんなときはfor文

  • 繰り返し回数が最初からわかっている
  • 配列やリストのインデックスが必要
  • 逆順で処理したい
  • 一定の間隔で処理したい(2つ飛ばし、など)
// 配列を逆順で処理
int[] numbers = { 1, 2, 3, 4, 5 };
for (int i = numbers.Length - 1; i >= 0; i--) {
    Console.WriteLine($"逆順: {numbers[i]}");
}

// 2つ飛ばしで処理
for (int i = 0; i < 10; i += 2) {
    Console.WriteLine($"偶数のインデックス: {i}");
}

while文を選ぶべき場面

✅ こんなときはwhile文

  • 繰り返し回数が最初はわからない
  • ユーザーの入力によって終了条件が決まる
  • 外部の状態変化を待つ
  • 条件が複雑
// ファイルの読み込み(最後まで読む)
using (StreamReader reader = new StreamReader("data.txt")) {
    string line;
    while ((line = reader.ReadLine()) != null) {
        Console.WriteLine(line);
    }
}

foreach文を選ぶべき場面

✅ こんなときはforeach文

  • コレクションのすべての要素を処理したい
  • インデックスが不要
  • 読み取り専用の処理
  • コードを简潔に書きたい
// ディクショナリの全要素を表示
Dictionary<string, string> settings = GetSettings();
foreach (var setting in settings) {
    Console.WriteLine($"{setting.Key}: {setting.Value}");
}

判断フローチャート

コレクション(配列・リスト等)を処理する?
├─ はい
│  ├─ インデックスが必要?
│  │  ├─ はい → for文
│  │  └─ いいえ → foreach文
│  └─ 特殊な順序で処理?
│     ├─ はい → for文
│     └─ いいえ → foreach文
└─ いいえ
   ├─ 繰り返し回数がわかっている?
   │  ├─ はい → for文
   │  └─ いいえ → while文
   └─ 条件によって繰り返す?
      └─ はい → while文

パフォーマンスと実用的なテクニック

ループの効率を上げるコツ

ループの外で変数を宣言

// 良い例:ループの外で宣言
StringBuilder result = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    result.Append(i.ToString());
}

// 悪い例:毎回新しいオブジェクトを作成
string result = "";
for (int i = 0; i < 1000; i++) {
    result += i.ToString(); // 非効率
}

必要以上にループしない

List<string> names = GetLargeNameList();

// 最初に見つかったら終了
string targetName = "田中";
foreach (string name in names) {
    if (name == targetName) {
        Console.WriteLine("見つかりました!");
        break; // ループを抜ける
    }
}

エラーハンドリング

int[] numbers = { 1, 2, 3, 4, 5 };

try {
    for (int i = 0; i <= numbers.Length; i++) { // 意図的にバグ
        Console.WriteLine(numbers[i]);
    }
} catch (IndexOutOfRangeException ex) {
    Console.WriteLine($"配列の範囲外アクセス: {ex.Message}");
}

実際の開発でよく使うパターン

ページング処理

List<string> allItems = GetAllItems(); // 大量のデータ
int pageSize = 10;
int pageCount = (int)Math.Ceiling((double)allItems.Count / pageSize);

for (int page = 0; page < pageCount; page++) {
    Console.WriteLine($"--- ページ {page + 1} ---");
    
    int startIndex = page * pageSize;
    int endIndex = Math.Min(startIndex + pageSize, allItems.Count);
    
    for (int i = startIndex; i < endIndex; i++) {
        Console.WriteLine($"{i + 1}: {allItems[i]}");
    }
}

進捗表示付きの処理

List<string> files = GetFileList();
int total = files.Count;

for (int i = 0; i < total; i++) {
    string file = files[i];
    
    // ファイル処理
    ProcessFile(file);
    
    // 進捗表示
    double progress = (double)(i + 1) / total * 100;
    Console.WriteLine($"進捗: {progress:F1}% ({i + 1}/{total})");
}

まとめ:ループ処理をマスターして効率的なプログラミングを

C#のループ処理は、プログラミングの基礎中の基礎でありながら、非常に強力な機能です。3つのループ文それぞれに特徴と適した場面があります。

重要なポイントの復習

for文

  • 繰り返し回数が明確なときに使用
  • インデックスが必要な処理に最適
  • 初期化、条件、更新が1行で書ける

while文

  • 条件に基づいた柔軟な繰り返し
  • 繰り返し回数が不明な場合に使用
  • ユーザー入力や外部条件待ちに便利

foreach文

  • コレクションの全要素を簡潔に処理
  • インデックス管理が不要
  • 読み取り専用の処理に最適

コメント

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