このページの概要
- RubyにはBASIC時代の悪名高い(?)gotoがありませんが、条件分岐と繰り返しを理解することによって、プログラミングを順次実行だけではない次のステップへと移行できます。
- 繰り返しは説明の便宜上 printf を使っています。printf("数字ですよ「%d」",x) で 数字ですよ「1」 みたいに x の中身を数字で表示せよ、という形式で使っているため、そんなに難しくはないと思います。書式の詳細はRubyリファレンスマニュアルのsprintfフォーマットをどうぞ。
- 動作確認環境 : Ruby 1.8.4
基本は上から下へ。
下のコードを実行すると、
2[改行]3[改行]4[改行]5[改行]6[改行]
と表示されます。つまり、上(2行目)から下まで順番に実行されて、最後の行(6行目)で処理が終わったということを意味します。
0
1
2
3
4
5
| | puts __LINE__ puts __LINE__ puts __LINE__ puts __LINE__ puts __LINE__
|
もし○○なら (if分岐)
もし○○なら××しなさい、という処理は、if(条件式) thenという文で行います。
次の行から end がくるまでの間は、条件式を満たす場合は実行され、条件式を満たさない場合はスキップされます。(if 以外にも、その行からendまでの間××する、という書き方はかなりあります。区別をしやすいように、そのような部分は半角スペース2文字の字下げを行ってください。)
then は if(条件式)で改行を入れる場合は省略できますが、入れた方がいいでしょう。
下記コードの場合、1以上の数字をキー入力したら 4 6 7 8 が表示されますが、0以下や文字を入れた場合だと 6 7 8 だけとなり、4行目がスキップされたことがわかります。
0
1
2
3
4
5
6
7
| | input = gets.to_i
if(input >= 1) then
puts __LINE__ end
puts __LINE__ puts __LINE__ puts __LINE__
|
1~だけではなく、1~10 の間の処理をしたい場合は、2通りの書き方があります。
- if の中に if を書く方法 (「もし 1~ならば」、の中に「もし~10ならば」を入れる)
0
1
2
3
4
5
6
7
8
9
10
| | input = gets.to_i
puts __LINE__ if(input >= 1) then
if(input <= 10) then
puts __LINE__ end
end
puts __LINE__ puts __LINE__ puts __LINE__
|
- ひとつの if の中に &&(AND式) や ||(OR式) を書く方法 (「もし 1~ならば」かつ(AND)「もし~10ならば」とする)
0
1
2
3
4
5
6
7
8
| | input = gets.to_i
puts __LINE__ if((input >= 1) && (input <= 10)) then
puts __LINE__ end
puts __LINE__ puts __LINE__ puts __LINE__
|
もし○○なら、そしてもし△△なら、そしていずれも違ったら (if then elsif then else分岐)
入力された値が1~10の場合、11~20の場合、それ以外の場合で処理を分けたいと思った場合は、if と end の間に elsif then と else を配置して条件分岐できます。then は改行があれば省略可能です。elsif(他の条件式) や else(if と elsif の条件をすべて満たさない場合) も分岐処理不要なら省略できます。
0
1
2
3
4
5
6
7
8
9
10
11
12
| | input = gets.to_i
puts __LINE__ if((input >= 1) && (input <= 10)) then
puts __LINE__ elsif((input >= 11) && (input <= 20)) then
puts __LINE__ else puts __LINE__ end
puts __LINE__ puts __LINE__ puts __LINE__
|
もし○○じゃなかったら、そして○○だったら (unless then else分岐)
if(!条件式) then は、 unless(条件式) then に置き換えることもできます。ただし、elsif が使えません。つまり、最大でも「○○と違うか、○○か」の二者択一になります。
0
1
2
3
4
5
6
7
8
9
10
| | input = gets.to_i
puts __LINE__ unless((input >= 1) && (input <= 10)) then
puts __LINE__ else
puts __LINE__ end
puts __LINE__ puts __LINE__ puts __LINE__
|
このケースだったら○○、あのケースだったら△△、該当しなかったら
(case when when else end 分岐)
1~10のときは○○、11~20のときは△△、21~30のときは××...という処理を if 分岐で書くのは大変ですが、Rubyだと case when という文を使ってすっきり書くことができます。when 部分には 1..10 といった書式が使えるので、かなり可読性に貢献すると考えられます。
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| | input = gets.to_i
puts __LINE__
case input
when 1..10
puts __LINE__ when 11..20
puts __LINE__ else
puts __LINE__ end
puts __LINE__ puts __LINE__ puts __LINE__
|
指定回数繰り返す (forによる繰り返し)
x 回繰り返ししたい処理がある場合は、for i in 1..x という記述で可能です。
0
1
2
3
4
5
6
7
8
| |
printf("Line:%d\n",__LINE__)
for i in 1..10
printf("Line:%d, Count:%d\n",__LINE__,i) end
printf("Line:%d\n",__LINE__)
|
1..x (1~x で x 回繰り返し) だけではなく、[x, y, z] の配列形式の書式(または配列型の変数)を渡すことにより、1 2 3 5 7 11 みたいな変則的な実行も可能です。
0
1
2
3
4
5
6
7
8
| |
printf("Line:%d\n",__LINE__)
for i in [1, 2, 3, 5, 7, 11]
printf("Line:%d, Count:%d\n",__LINE__,i) end
printf("Line:%d\n",__LINE__)
|
特定条件を見て繰り返す (whileによる繰り返し、untilによる繰り返し)
特定の条件を満たし続ける限り、繰り返しし続けるという構文 while があります。一方で、特定の条件を*満たさない限り*繰り返しし続ける構文 until もあります。
0
1
2
3
4
5
6
7
8
9
10
| |
printf("Line:%d\n",__LINE__)
i = 0
while (i<=5)
printf("Line:%d, Count:%d\n",__LINE__,i) i = i + 1 end
printf("Line:%d\n",__LINE__)
|
0
1
2
3
4
5
6
7
8
9
10
| |
printf("Line:%d\n",__LINE__)
i = 0
until (i>5) printf("Line:%d, Count:%d\n",__LINE__,i) i = i + 1
end
printf("Line:%d\n",__LINE__)
|
上のコードでは、わかりやすいように数字の大小を繰り返し条件としていますが、実際にはキー入力やファイル処理・ネットワーク通信の「終了を検知するまで」繰り返させる、というのが一般的です。
イテレータ (配列名.each do |取り出し変数| ... end または 配列名.each {|取り出し変数| ... })
for i in 1..10 の応用みたいな方法として、イテレータというものがあります。
範囲を示す変数(Range、1..10がいい例)や配列型(Array, ["a","bb","ccc"] が例)を筆頭に、each で変数をひとつずつ取り出して、範囲や配列が終わるまでループさせる、というのがその役割です。
下のサンプルは2通りの書き方をしていますが、いずれも myloop という「範囲を示す変数」を最初から最後まで、1個ずつ value に取り出しながら繰り返ししています。個人的には { } を使っていない前者の方が Ruby らしいと思います。
0
1
2
3
4
5
6
7
8
9
10
11
| | myloop = 1..10
myloop.each do |value|
puts value
end
myloop.each {|value|
puts value
}
|
イテレータ (times や upto を使うケース)
「myloop = 1..10」といった定義をしなくても繰り返しする方法があります。10回繰り返すコードを2通り書いてみましょう。
0
1
2
3
4
5
6
7
8
9
| | 10.times do |value|
puts value end
1.upto(10) do |value|
puts value end
|
中断されない限り無限ループ (loop)
構文 loop { }を使うと、break exit 等のループ脱出のキーワードを使うか、CTRL+C 等でスクリプトを強制中断しない限り無限ループとなります。なお、この loop はイテレータの一種のようで、loop = 範囲型/配列型の値 をいれてやると、無限ループではなくなってしまいます(loop の役割が上書きされてしまう)。loop 変数の取り扱いにはいろいろな意味で注意しましょう。
0
1
2
3
| | loop {
puts __LINE__ }
|
繰り返しの流れを変更する
(end 以降へジャンプする break、条件式直前へジャンプする next、条件式直後へジャンプする redo、評価やりなおしの retry)
for while loop といった繰り返し文の途中で処理の流れを換えることができます。
break next redo retry がそのキーワードです。これらのキーワードは「最も内側の繰り返し」に作用してコードの実行順序を変更することができます。
- 繰り返し終了 break のサンプル
0
1
2
3
4
5
6
7
8
| | for i in 1..10
if (i == 7) then
break end
puts i
end
|
- 繰り返しを次ステップへ進める next のサンプル
0
1
2
3
4
5
6
7
| | for i in 1..10 if (i == 7) then
next end
puts i
end
|
- 条件式を確認せずに繰り返しをやり直す redo のサンプル
0
1
2
3
4
5
6
7
8
9
| | for i in 1..10
printf(" _")
if (i == 7) then
redo end
puts i
end
|
- 繰り返しを「再起動」してしまう retry のサンプル
0
1
2
3
4
5
6
7
| | for i in 1..10 if (i == 7) then
retry end
puts i
end
|
break next redo retry の各キーワードは、if (条件) then break; end を break if (条件) のように記述することもできます。