前半の内容
前半はfor文でのループを学習しました。後半は最も良く使うであろうforeach文でのループを学習していきます。ちなみに読み方は「フォーイーチ」です。
前回作成した「1から10の整数を全て足した結果を画面に表示する」プログラムのfor文を使用した例を再掲しておきます。
public int Sum = 0;
public void OnGet()
{
int adder = 0;
for (int i = 0; i < 10; i++)
{
adder += 1;
Sum += adder;
}
}
foreach文とは
今回は、上記のfor文を使用したプログラムを、foreach文で書き換えた例をお見せしてから解説していきます。
public int Sum = 0;
public void OnGet()
{
int[] addends = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach (var item in addends)
{
Sum += item;
}
}
foreach文はいくつかの値の集合から、1つずつ値を取り出してループする命令です。値の集合のことをコレクション、集合に含まれる各値を要素と言います。この例では下記の文でコレクションを作成しています。
int[] addends = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
変数「addends」を宣言して初期値を代入していますが、これまでの変数とは様子が違います。これは配列という、コレクションの一種です。
配列の説明
配列とはコレクションの一種で、最も原始的なものです。どんなプログラミング言語の学習でも必ずと言っていいほど出てきますが、C#においてはもっと便利なコレクションがあるため基本的には使いません。ただ、配列の概念はコレクションの基本なので覚えておきましょう。今回の例では変数「addends」が配列です。
型の指定
型の指定部分のintの後ろに[]がありますね。これにより、ここで宣言する変数が配列になります。[]の前に記述した型が要素の型となりますので、今回の例ではint型の要素を持つ配列となります。
初期値の書き方
配列の初期値は{}の中に、要素をカンマ区切りで指定します。今回の例では1から10の整数それぞれが要素になります。全部で10個の要素を持っていることになります。
配列の要素の取得、変更
配列の各要素は変数名[インデックス]の形式で操作できます。インデックスとは要素の格納されている位置(順番)を表す数値です。最初の要素のインデックスは0となりますので注意してください。C#以外のほとんどの言語でもインデックスは0から始まりますが、1から始まるものもありますので、言語ごとに確認が必要です。また、インデックスは「添字」とも言います。
public int Sum = 0;
public void OnGet()
{
int[] addends = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach (var item in addends)
{
// 値の変更例 最初の要素を100に変更
addends[0] = 100;
// 値の取得例 Sumは110になる
Sum = addends[0] + addends[9];
}
}
なお、foreach文で使用した場合はインデックスを指定することなく、最初の要素から順番に1つずつ取り出されて、全ての要素を取り出すまでループします。
配列にまつわるその他のこと(覚えなくていいです)
・配列は基本的に要素の追加、削除はできません。最初に要素数を決めたら変更できないということです。ただし、Pythonという言語では、配列という呼び名でも非常に高度な機能を持っており、他の言語とは異なる特徴があります。
・配列には次元という概念があり、1次元配列、2次元配列、・・・、多次元配列というものを見たり聞いたりしたことがある方もいると思います。今回使用しているのは一番単純な1次元配列ですが、2次元以上の配列を使用するとプログラムが非常にややこしくなります。現時点でこれを覚える必要性は全くありませんし、どうしても必要な時だけ使用してください。ここではあえて詳細に触れずにおきます。
foreach文の構文
foreach文の構文は以下の通りです。
foreach (要素の型 要素用の変数 in コレクション)
{
処理ブロック
}
コレクションから要素を1つずつ取り出してループしますが、取り出した要素は要素用の変数に格納されています。処理ブロックの中ではその変数を参照することで、その要素に関する処理を行えます。処理ブロックの中では、その時取り出された要素のみ変数に格納されていますので、複数の要素を同時に処理することはできません。
varという暗黙の型指定について
前述の配列を使用したforeach文の例では、要素の型にvarというものを指定しています。これは暗黙の型指定と呼ばれる、特別な型指定です。今回の例では要素の型は「int」を指定しても同じ結果となります。しかし、この例では「int型の要素を持つ配列」から要素を取り出すので、要素の方は「int」であることが明白です。このように、変数に代入する値から、型が暗黙的に特定できる場合は「var」を指定することができます。ただし、「var」は型の記述を簡略化する意味しかないため、必ず使用する必要があるわけではありません。
Visual Studio の機能で”foreach”と入力した後にtabキーを2回押すと、コードスニペットというひな形を自動で作成できます。この機能を用いると「var」が指定されるので、今回はそのままにしました。このように自動で指定される場合はあまり気にする必要はありませんが、しっかりと型を意識してプログラミングできるようになるまでは、「var」ではなく、「int」の様に型を明示した方が良いでしょう。
Listを使用したforeach
先ほどはコレクションとして配列を使用しましたが、Listという高機能なコレクションを使用してみましょう。
public int Sum = 0;
public void OnGet()
{
List<int> addends = Enumerable.Range(1,10).ToList();
foreach (int item in addends)
{
Sum += item;
}
}
型の指定
変数宣言の型指定部分に注目してください。配列とは異なる書き方になりますが、これでint型の要素をもつList型の変数を宣言できます。
初期値の指定
初期値の指定は、C#で元々用意されている機能を利用して要素に連続した整数を持つListを作成しています。これは特に覚えておく必要はありませんが、単純な処理であれば言語で機能が用意されていることも多くありますので、Webで調べてみるといいです。これは私もWebで検索して調べて見つけました。この機能も一応説明しておきます。
Enumerable.Range(1,10)
この部分で1から始まる10個の連続した整数を生成しています。「10」の指定は作成する数値の個数なので注意してください。
Enumerable.Range(0,10)
とすれば0から9までの整数となります。
.ToList()
の部分で作成した整数をList型のコレクションにしています。
Listの説明
今回の例だと、配列ではなくListを使うメリットが無いように感じますが、実は、Listを使うともっと簡単に同じことができてしまいます。下記の例を見て実際に実行してみてください。
public int Sum = 0;
public void OnGet()
{
List<int> addends = Enumerable.Range(1, 10).ToList();
Sum = addends.Sum();
}
いかかでしょうか? List型には色々と機能が用意されていて、「Sum()」という機能で要素の合計を求めています。基本的な機能としては、要素の追加・削除があります。他にも要素の並べ替え(ソートと言います)や検索等の機能があります。Listの基本的な使い方を下記に示しておきます。書き写して、デバッグ実行で1行ずつ動作を確認してみてください。addendsをウォッチすると変化がわかります。
public void OnGet()
{
// 「new List<要素の型>()」で空のListを作成できる。Listを使う場合は必ず初期化してから使用する。
List<int> addends = new List<int>();
for (int i = 1; i <= 10; i++)
{
// Listの最後の位置に要素を追加する。リストの途中の位置に追加したい場合はAddではなくInsertを使用する。
addends.Add(i);
}
// 配列と同じようにインデックスを指定した値の取得・変更が可能。
addends[0] = 5;
// 指定したインデックスの要素を削除する。
addends.RemoveAt(2);
// 指定した値を持つ要素を削除する。同じ値の要素が複数あった場合はインデックスの一番小さいものだけが削除される。
addends.Remove(5);
}
その他のループ命令
C#ではfor文、foreach文以外に、while文とdo-while文というループ命令があります。どちらもwhile(条件式)で記述した条件を満たしている間、ループします。しかし、do-whileは他のループ命令と違って、条件評価が行われるタイミングが処理実行後となるため、最低でも1回は処理が行われます。以下の例を実際にデバッグ実行して違いを確認してみてください。まずはforeach文、for文が使用できればいいですが、while文も使うことはありますのでなんとなくでも覚えておきましょう。do-while文はあまり使わないので覚える必要はないですが、while文とは違うということだけ認識しておいてください。
public int Sum = 0;
public void OnGet()
{
int count = 1;
while (count > 10)
{
Sum += count;
count++;
}
}
public int Sum = 0;
public void OnGet()
{
int count = 1;
do
{
Sum += count;
count++;
} while (count > 10);
}
処理ブロックでループを制御するbreakとcontinueについて
ループの処理ブロックで、ある条件に当てはまる時にループを抜けたい場合に使用する命令として、breakがあります。
また、処理ブロックをスキップして次のループに移りたい場合に使用する命令として、continueがあります。
ループの処理が複雑になる場合に使用することで、プログラムのコードが簡潔になる場合があります。ループで必ず使用する命令ではありませんが、覚えておくと良いでしょう。
下記に例を示しますので、書き写して、デバッグ実行で1行ずつ動作を確認してみてください。
public int Sum = 0;
public void OnGet()
{
for (int i = 1; i <= 100; i++)
{
// 合計が10以上なら break:ループを抜ける
if (Sum >= 10)
{
break;
}
// iが奇数なら continue:以降の処理をスキップして次のループに移る
if (i % 2 == 1)
{
continue;
}
Sum += i;
}
}
なお、上の例の中でif ( 条件式 ) { 中略 }という記述がありますが、これは条件分岐といって条件式を満たす場合のみ処理を行う命令です。詳しくは次回の第6回講座で解説します。
また、条件式に指定している
i % 2 == 1
は「変数iを2で割った余りが1である」という記述で、「変数iが奇数である」ということを意味しています。%は剰余(割り算した余り)を求めるための記号です。+や–等と同じ様に使います。これらの記号を演算子と言いますが、演算子の種類については第6回および第7回講座で詳しく解説します。
ループとコレクション
いかがでしたでしょうか。ループと配列やList等のコレクションについてなんとなくイメージできたでしょうか。現時点で完璧に理解する必要はありません。実際にプログラミングをしていく中で、「ループやコレクションを使えばできそうだな」と感じられれば大丈夫です。使いながら理解を深めてください。
今回は以上となります。お疲れさまでした。
早速の修正ありがとうございました。よく分かりました。
こちらこそお手間をおかけして申し訳ありません。
今後ともよろしくお願いいたします。
いつも楽しく勉強させていただいております。
今回の記事で,whileとdo-whileの違いが分からなかったのですが,
どの部分が異なるのでしょうか?
お忙しいところ申し訳ありませんがご教示いただけますと幸いです。
コメントありがとうございます。
記事に掲載したコードが間違って、while文と同じものになっていました。
すぐに修正しますのでお待ちください。
修正しました。
余計なお時間を取らせてしまいました。本当に申し訳ありません。
do-while文の例 の箇所を再度見ていただいて、デバッグ実行してもらえれば違いがわかると思います。
条件を満たしていなくても処理が1回実行されるので、結果として1が表示されます。