プログラミングをする上で、反復処理 (ループ処理) は欠かせない重要な機能の1つです。
反復処理を記述する方法はいくつかありますが、その中の1つに foreach文を使用する方法があります。
今回の記事では、C#で foreach文を使用する方法について解説していきます。
C#のforeachとは
foreach文は、配列やListなどのコレクションに対し、要素を順番に取り出して処理するための繰り返し構文です。
通常のfor文の場合、インデックス番号を使って各要素にアクセスする必要がありますが、foreach文では要素そのものを直接取得できるため、コードを簡潔かつ安全に記述できます。
主に、以下のようなコレクションに対して頻繁に使用されています。
- List
- 配列
- Dictionary
- Queue
- HashSet
listを使ってリストの中身を一つずつ取り出す方法
foreach文はListとの相性が非常に良く、実務でも多用されています。
具体的な使用方法について見ていきましょう。
基本の書き方とvarを使った便利な方法
foreachの基本構文は以下の通りです。
foreach (型名 変数名 in コレクション)
{
処理
}指定のコレクションの各要素が変数に格納され、ブロック内で使用することができます。
List<string> fruits = new List<string>()
{
"りんご",
"みかん",
"ぶどう"
};
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}りんご
みかん
ぶどうこのように、Listの要素を1つずつ順番に取得できます。
また、型推論の var を使うことで、より簡潔に記述できます。
foreach (var fruit in fruits)
{
Console.WriteLine(fruit);
}varはコンパイラが型を自動で判定してくれるため、複雑な型を扱う際などに便利です。
ただし、コードだけでは型が分かりづらくなるケースもあるため、状況に応じた使い分けが重要となります。
ループ中に中身を書き換えられない問題と解決策
foreach文を使用する際の注意点として、ループ処理中にコレクションの内容を変更すると、例外が発生する場合があります。
List<int> numbers = new List<int>()
{
1, 2, 3
};
foreach (var number in numbers)
{
numbers.Add(100);
}System.InvalidOperationException: Collection was modified; enumeration operation may not execute.これは、処理中にコレクションの構造が変化することにより、整合性が崩れて発生するエラーです。
主な解決策としては、以下の2点が挙げられます。
- for文を使用する
- コピーを作成する
可読性がより高いのは後者の方ですが、データ量が多い場合にコストがかかってしまうため、状況に応じて使い分けるのがベストです。
indexを使ってループ内で添え字を取得する方法
C#では、インデックスを取得する機能がforeach文にはありません。
そのため、インデックス操作が必要なケースにおいては、for文を使用するのが一般的です。
List<string> fruits = new List<string>()
{
"りんご",
"みかん",
"ぶどう"
};
for (int i = 0; i < fruits.Count; i++)
{
Console.WriteLine($"{i} : {fruits[i]}");
}0 : りんご
1 : みかん
2 : ぶどうLINQのSelectメソッドを用いてスマートにインデックスを取得する
LINQ の Select() を利用すると、foreach文を維持したままインデックスを扱えます。
foreach (var item in fruits.Select(
(value, index) => new { value, index }))
{
Console.WriteLine($"{item.index} : {item.value}");
}foreach文の可読性の高さを保ちつつ、インデックスを取得できるのがメリットです。
ただし、LINQは内部的にオブジェクト生成を伴うため、使用する場合はパフォーマンスへの影響も考慮する必要があります。
外部カウンタ変数を用いた従来手法との使い分けと注意点
従来では、外部変数でインデックス管理する方法もよく使われていました。
int index = 0;
foreach (var fruit in fruits)
{
Console.WriteLine($"{index} : {fruit}");
index++;
}シンプルな方法ですが、使用時には以下のデメリットが伴う場合があります。
- index更新忘れ
- 可読性低下
- ネスト時の管理複雑化
反復処理のパフォーマンスを最適化し、効率を向上させるコツ
通常のアプリケーションでは、foreach文の性能が問題になるケースは少ないですが、大量データを扱う際には差が出る場合があります。
そのため、状況に応じてパフォーマンスの最適化を行うことが重要です。
SpanやReadOnlySpanによるメモリ効率の改善
Span は、メモリコピーを避けながらデータを扱える高速機能です。
特に、以下の処理などに対して効果を発揮します。
- 大量文字列処理
- バイナリ解析
- 高速ループ
int[] numbers = { 1, 2, 3, 4 };
Span<int> span = numbers;
foreach (var number in span)
{
Console.WriteLine(number);
}ReadOnlySpan を使うと、読み取り専用として扱えます。
ReadOnlySpan<int> span = numbers;大規模なデータの走査における列挙速度の注意点
大規模なデータを扱う場合は、列挙方法による性能差が大きく影響するケースがあります。
例えば、以下のような処理方法は、速度低下の原因になり得ます。
- LINQチェーンの多用
- 不要なToList()
- foreach中の大量GC発生
大量データに対しては、for文・Span・配列直接操作などの方が、高速に処理できる場合があります。
ただし、可読性とのバランスも重要なため、実務では以下のように使い分けるケースが多く見られます。
- 通常処理 → foreach文 / LINQ
- 高負荷処理 → for文 / Span
まとめ
foreach文は、Listや配列などのコレクションを簡潔に反復処理できる便利な構文です。
ただし、コードの可読性向上や安全な列挙処理といったメリットがある一方で、ループ中の要素数の変更不可やインデックスの取得が不得手な点などの注意点も存在するため、用途に応じて for文などと使い分けることが重要です。
C#の勉強方法は?
書籍やインターネットで学習する方法があります。昨今では、YouTubeなどの動画サイトやエンジニアのコミュニティサイトなども充実していて多くの情報が手に入ります。
そして、より効率的に知識・スキルを習得するには、知識をつけながら実際に手を動かしてみるなど、インプットとアウトプットを繰り返していくことが重要です。特に独学の場合は、有識者に質問ができたりフィードバックをもらえるような環境があると、理解度が深まるでしょう。
ただ、C#に限らず、ITスキルを身につける際、どうしても課題にぶつかってしまうことはありますよね。特に独学だと、わからない部分をプロに質問できる機会を確保しにくく、モチベーションが続きにくいという側面があります。独学でモチベーションを維持する自信がない人にはプログラミングスクールという手もあります。費用は掛かりますが、その分スキルを身につけやすいです。しっかりと知識・スキルを習得して実践に活かしたいという人はプログラミングスクールがおすすめです。
プログラミングスクールならテックマニアがおすすめ!
ITスキル需要の高まりとともにプログラミングスクールも増えました。しかし、どのスクールに通うべきか迷ってしまう人もいるでしょう。そんな方にはテックマニアをおすすめします!これまで多くのITエンジニアを育成・輩出してきたテックマニアでもプログラミングスクールを開講しています。
<テックマニアの特徴>
・たしかな育成実績と親身な教育 ~セカンドキャリアを全力支援~
・講師が現役エンジニア ~“本当”の開発ノウハウを直に学べる~
・専属講師が学習を徹底サポート ~「わからない」を徹底解決~
・実務ベースでスキルを習得 ~実践的な凝縮カリキュラム~
このような特徴を持つテックマニアはITエンジニアのスタートラインとして最適です。
話を聞きたい・詳しく知りたいという方はこちらからお気軽にお問い合わせください。