C#のforeach文を使いこなすことで、コレクションや配列といった複数の要素を持つデータ構造を効率的に処理できます。
この記事では、foreach文の基本構文から、LINQとの連携、パフォーマンス改善といった応用的な使い方までを網羅的に解説します。
目次
1. C#のforeachとは:基本構文と使い方
C#におけるforeach文は、コレクションや配列などの要素を順番に処理するための基本的な構文です。for文よりも簡潔にコレクションの要素にアクセスできるため、コードの可読性が向上します。
この章では、foreach文の基本構文からfor文との違いについて、具体的なコード例とともに解説します。
C# foreachの基本構文
foreach文は、C#においてコレクションや配列などの要素を順番に処理するための構文です。for文のようにインデックスを管理する必要がなく、より簡潔にコレクションの要素にアクセスできます。foreach文を使用することで、コードの可読性が向上し記述ミスを減らせます。
foreach文の基本構文は以下のとおりです。
foreach (型名 変数名 in コレクション) { // 変数を使った処理 } |
型名にはコレクション内の要素の型を指定し、変数名にはコレクションから取り出した要素を格納する変数を指定します。コレクションには、反復処理を行う対象のコレクション(配列、Listなど)を指定します。
具体的な例は以下のとおりです。
List<string> names = new List<string>() { "Alice", "Bob", "Charlie" };
{ Console.WriteLine(name); } |
この例では、namesリストの各要素(文字列)が順番にname変数に格納され、コンソールに出力されます。
foreachループはコレクションの最初の要素から最後の要素まで自動的に処理するため、インデックス管理が不要で、コードが簡潔になります。
forとforeachの違いと使い分け
for文とforeach文は、どちらもループ処理を行うための構文ですが、それぞれ得意とする処理が異なります。
for文は、インデックスを明示的に制御する必要がある場合や、ループの回数を事前に指定する場合に適しています。一方、foreach文は、コレクションの要素を順番に処理する場合に、より簡潔に記述できます。
for文の利点は以下のとおりです。
インデックスを自由に操作できるため、特定の条件でループをスキップしたり、逆順に処理したりできます。
ループの回数を事前に指定できるため、パフォーマンスを最適化できます。
要素の変更が可能です。
一方、foreach文の利点は以下になります。
コレクションの要素を順番に処理するため、コードが簡潔で読みやすくなります。
インデックスを管理する必要がないため、記述ミスを減らせます。
要素自体は読み取り専用で変更不可です。
使い分けの例は以下のとおりです。
// forループの例:特定範囲の処理やインデックスが必要な場合 int[] numbers = { 1, 2, 3, 4, 5 }; for (int i = 0; i < numbers.Length; i++) { // インデックスを使った処理 numbers[i] = numbers[i] * 2; // 要素の値を変更 Console.WriteLine($"Index {i}: {numbers[i]}"); }
foreach (int number in numbers) { // シンプルに各要素を処理 Console.WriteLine(number); // number = number * 2; // エラー:foreachの反復変数は代入不可 } |
コレクションの要素を順番に処理する場合はforeach文、インデックスを操作する必要がある場合やループの回数を事前に指定する場合は、for文を使用するのがよいでしょう。
ちなみに、パフォーマンスの観点では、配列に対しては両者の差はあまりありません。ただしforループは明示的なインデックス操作が可能なため、特定の処理ではforループの方が適している場合があります。パフォーマンスが求められる場合は、for文とforeach文のパフォーマンスを比較して適切な方を選択しましょう。
2. C# foreachでのコレクション操作
C#では、List、Array、Dictionaryといったさまざまなコレクション型に対してforeach文を適用することで、要素へのアクセスや処理を簡単に行えます。
この章では、foreach文で使用できるコレクション型の一覧とその使い方、foreach文を使ってリストに要素を格納する方法について解説します。
C# foreachで使えるコレクション型:List, Arrayなど
C#のforeach文は、IEnumerableインタフェースを実装したコレクション型であれば、どのような型でも使用できます。
主なコレクション型としては、以下のものがあります。
配列(Array)
リスト(List<T>)
ディクショナリ(Dictionary<TKey, TValue>)
キュー(Queue<T>)
スタック(Stack<T>)
List<T>とDictionary<TKey, TValue>を使った実装例を見てみましょう。
// リストの作成と初期化 List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
foreach (int number in numbers) { Console.WriteLine(number); }
Dictionary<string, int> ages = new Dictionary<string, int> { { "山田", 30 }, { "鈴木", 25 }, { "佐藤", 40 } };
foreach (KeyValuePair<string, int> person in ages) { Console.WriteLine($"{person.Key}さんは{person.Value}歳です"); } |
このように、foreachループは様々なコレクション型に対応しています。
C# foreachでリストに格納する方法
foreach文を使って既存のコレクションから新しいリストを生成するには、List<T>.Add()メソッドを使用します。
実装例は以下のとおりです。
// 元のデータ int[] sourceNumbers = { 1, 2, 3, 4, 5 };
List<int> evenNumbers = new List<int>();
foreach (int number in sourceNumbers) { if (number % 2 == 0) // 偶数の場合 { evenNumbers.Add(number); } }
Console.WriteLine("偶数のみ:"); foreach (int number in evenNumbers) { Console.WriteLine(number); } |
foreach文を使って、既存のコレクションからリストに格納するパターンとしては、以下が挙げられます。
フィルタリング: 条件に一致する要素だけを新しいリストに追加
変換: 各要素を加工してから新しいリストに追加
集計: 特定の条件に合う要素だけをカウントまたは合計
ただ、これらの操作は後述するLINQを使うとさらに簡潔に記述できます。LINQの使い方はこのあと解説します。
関連記事
【C#】Listと配列との違いや初期化・削除・要素数取得・型指定なしの使い方を紹介
3. C# foreachとLINQの連携
C#におけるLINQ(Language Integrated Query)は、効率的にコレクションを操作できる機能です。データのフィルタリング、変換、集計などを簡単に行えるため、foreachループと併用することで複雑なデータ操作も直感的に実現できます。
この章では、ラムダ式を活用したLINQの基本的な使い方や、foreachループとの連携による実践的なコード例を紹介します。
C# foreachとラムダ式の活用パターン
ラムダ式は、匿名メソッドを簡潔に記述するための構文です。C#では、ラムダ式を活用することでforeachループをより簡潔に記述できます。
foreachとラムダ式の活用パターンは以下のとおりです。
List<string> names = new List<string> { "山田", "鈴木", "佐藤" };
names.ForEach(name => Console.WriteLine($"こんにちは、{name}さん")); |
これはList<T>クラスのForEachメソッドを使った例です。foreach文と同様の処理をより簡潔に記述できます。
また、複雑な処理をラムダ式として定義することもできます。
using System; using System.Collections.Generic;
{ public static void Main(string[] args) { List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6 };
{ if (number % 2 == 0) { Console.WriteLine(number); } }); } } |
この例では、numbers.ForEach()メソッドにラムダ式を渡すことで、リストの各要素に対して偶数かどうかを判定し、偶数の場合はコンソールに出力しています。
C# foreachとLINQを使った簡潔なコード実装
LINQを使用すると、コレクションのフィルタリング、変換、集計などの処理をSQLのような構文で記述できます。
foreach文とLINQを組み合わせることで、より複雑なデータ操作も簡潔に記述できます。
基本的なLINQクエリの例は以下の通りです。
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var evenNumbers = numbers.Where(n => n % 2 == 0);
foreach (var number in evenNumbers) { Console.WriteLine(number); } |
この例では、リストの各要素に対して偶数かどうかを判定し、偶数の場合はコンソールに出力しています。ラムダ式で紹介したコードと同じ処理をしているので、記述量の違いを見比べてみましょう。
また、複数のLINQ操作を連鎖させたり、foreachと組み合わせたりすることも可能です。
using System; using System.Collections.Generic; using System.Linq;
{ public static void Main(string[] args) { List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6 };
List<int> squaredEvenNumbers = numbers .Where(number => number % 2 == 0) // 偶数を抽出 .Select(number => number * number) // 2乗する .ToList(); // リストに変換
foreach (int number in squaredEvenNumbers) { Console.WriteLine(number); } } } |
この例では、LINQのWhere()メソッドで偶数を抽出し、Select()メソッドで各要素を2乗し、ToList()メソッドで新しいリストを生成しています。その後、foreach文を使って生成されたリストの要素をコンソールに出力します。
このように、LINQとforeachを組み合わせることで、データの抽出、変換、集計などの操作をより簡潔かつ可読性の高い方法で実装できます。複雑なデータ処理や多段階のフィルタリングが必要な場合は、LINQを活用するのがおすすめです。
4. C# foreachの高度な使い方
C#のforeachループは、コレクション内の要素を効率的に処理するための基本構文ですが、応用次第でさらに高度な使い方が可能です。
この章では、foreach文の高度な使い方として以下の3点を紹介します。
参照渡しと値渡し
ループを途中で抜ける方法
2重ループの実装方法と抜ける方法
これらのテクニックを習得することで、foreach文をより効果的に活用できるようになりましょう。
C# foreach の参照渡しと値渡し
C#のforeachループでは、通常、コレクション内の要素のコピーが変数に代入されます。しかし、参照型の場合は元のオブジェクトに対する参照が渡される点に注意が必要です。
このため参照型の場合、オブジェクトのプロパティを変更すると元のコレクション内のオブジェクトも変更されます。
リストの文字列を大文字に変換する処理を例に値渡しと参照渡しの違いを説明します。
以下は値渡しでリストの文字列を大文字に変換する処理です。
using System; using System.Collections.Generic;
{ public static void Main(string[] args) { List<string> names = new List<string>() { "alice", "bob", "charlie" };
{ string temp = name.ToUpper(); // 文字列を大文字に変換 (これは元のリストに影響しない) }
foreach (string name in names) { Console.WriteLine(name); // 結果: alice, bob, charlie (元のリストは変更されていない) }
for (int i = 0; i < names.Count; i++) { names[i] = names[i].ToUpper(); }
foreach (string name in names) { Console.WriteLine(name); // 結果: ALICE, BOB, CHARLIE (リストが変更された) } } } |
この例では、foreach文の中でname変数を大文字に変換していますが、元のnamesリストは変更されていません。これは、stringが不変(immutable)な型であるためです。
stringの値を変更すると新しいstringオブジェクトが作成されるため、元のnamesリストの要素は変更されません。元のnamesリストを更新するには、インデックスを更新するか新しいリストを作成する必要があります。
しかし、参照型のオブジェクトのプロパティを変更する場合は、元のコレクションも変更されます。
using System; using System.Collections.Generic;
{ public string Name { get; set; } }
{ public static void Main(string[] args) { List<Person> people = new List<Person>() { new Person { Name = "alice" }, new Person { Name = "bob" }, new Person { Name = "charlie" } };
{ person.Name = person.Name.ToUpper(); // オブジェクトのプロパティを変更 }
foreach (Person person in people) { Console.WriteLine(person.Name); // 結果: ALICE, BOB, CHARLIE (リストが変更された) } } } |
この例では、foreach文の中でperson.Nameプロパティを大文字に変換しており、元のpeopleリストも変更されています。これは、personが参照型であり、foreach文がpersonオブジェクトへの参照を渡しているためです。
参照渡しによる予期せぬ変更を防ぐには、foreach文の中で要素のコピーを作成して処理するか、新しいリストを作成する必要があります。
C# foreach ループを途中で抜ける方法
特定条件でforeachループから抜けたい場合は、breakキーワードを使用します。また、特定の条件で現在の反復処理のみスキップしたい場合はcontinueキーワードが便利です。
continueやbreakを使用してforeachループを途中で抜ける処理の例は、以下のとおりです。
using System;
{ static void Main() { string[] names = { "Alice", "Bob", "Charlie", "David" };
{ if (name == "Charlie") { Console.WriteLine("Match found! Stopping iteration."); break; // Charlieが見つかったらループ終了 }
{ Console.WriteLine("Skipping names starting with A..."); continue; // Aで始まる名前はスキップ }
} } } |
このコードでは、breakによってCharlieが見つかった時点でループが終了し、continueによってAで始まる名前がスキップされます。
C# foreach の2重ループ:実装方法と抜ける方法
2重foreachループは、ネストしたコレクション(リストのリスト、2次元配列など)を処理する際に使用します。
基本的な構文は以下のとおりです。
// 外側のコレクションに対するループ foreach (var outerItem in outerCollection) { // 内側のコレクションに対するループ foreach (var innerItem in innerCollection) { // 処理内容 } } |
foreachの2重ループを使うと、2次元配列の要素を出力できます。
// 2次元配列の処理 int[][] matrix = new int[][] { new int[] { 1, 2, 3 }, new int[] { 4, 5, 6 }, new int[] { 7, 8, 9 } };
foreach (int[] row in matrix) { // 内側のループで各行の要素を処理 foreach (int cell in row) { Console.Write($"{cell} "); } Console.WriteLine(); // 行の終わりで改行 } |
C#のforeachでループを抜け出すにはbreakを使用します。しかし、breakで抜け出せるのは内側のループのみです。このため、2重ループ全体から抜け出すには工夫が必要です。
ここでは2重ループから抜け出す方法として以下の2つを紹介します。
フラグ変数を使用する方法
メソッド化してreturnを使用する方法
以下のコードはフラグ変数を使用して、外側のループを制御する方法の実装例です。
using System;
{ public static void Main(string[] args) { int[,] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
{ for (int j = 0; j < matrix.GetLength(1); j++) { Console.Write(matrix[i, j] + " "); if (matrix[i, j] == 5) { found = true; // 条件を満たした場合、フラグ変数を設定 break; // 内側のループから抜ける } } Console.WriteLine();
{ break; // 外側のループから抜ける } } } } |
内側のループで特定の条件が満たされた場合にフラグ変数を設定します。その後、外側のループでフラグ変数の値を確認して、ループを抜け出すかどうかを判断します。
メソッド化してreturnを使用する方法の実装例は以下のとおりです。
using System;
{ public static void Main(string[] args) { int[,] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; ProcessMatrix(matrix); }
{ for (int i = 0; i < matrix.GetLength(0); i++) { for (int j = 0; j < matrix.GetLength(1); j++) { Console.Write(matrix[i, j] + " "); if (matrix[i, j] == 5) { Console.WriteLine("Found!"); return; // メソッドから抜ける } } Console.WriteLine(); } } } |
2重ループの処理をメソッドとして分割し、内側のループで特定の条件が満たされた場合にreturnステートメントを使用してメソッドから抜け出すことで、2重ループ全体から抜け出せます。
関連記事
C#とは?基本文法や特徴、メリット、開発分野まで初心者に必要な情報をわかりやすく解説
5.まとめ
この記事では、C#におけるforeach文の基本から応用まで詳しく解説しました。
foreachを使うと、コレクションや配列といった複数の要素を持つデータ構造を効率的に処理できます。foreachをマスターすることで、コードの可読性と保守性が向上して、より効率的な開発ができます。
まずは、foreach文の基本構文、for文との使い分け、コレクション操作といった基本的なforeachの使い方をしっかりマスターしましょう。その上で、LINQやラムダ式と組み合わせてより簡潔にコードを記述する方法や、ループを途中で抜け出したり、2重ループを実装したりといった高度な使い方も習得するのがおすすめです。
foreach文を使いこなすことは、C#プログラミングのスキルアップに繋がり、開発効率の向上やコードの品質向上に貢献します。この記事で学んだ知識を活かし、日々のコーディングでforeach文を積極的に活用していきましょう。
本記事が皆様にとって少しでもお役に立てますと幸いです。
「フリーランスボード」は、数多くのフリーランスエージェントが掲載するITフリーランスエンジニア・ITフリーランス向けの案件・求人を一括検索できるサイトです。
開発環境、職種、単価、稼働形態、稼働日数など様々な条件から、あなたに最適なフリーランス案件・求人を簡単に見つけることができます。
単価アップを目指す方や、自分の得意なスキルを活かせる案件に参画したい方は、ぜひ「フリーランスボード」をご利用ください。