繰り返し
概要
プログラムでは条件分岐と並んで重要な繰り返しについて説明します。 何か処理のかたまりを一定の条件に従って繰り返すことを繰り返しといいます。
繰り返しとは
繰り返しとは何かの処理を繰り返し行うことです。 永遠に繰り返してしまうとプログラムが永遠に終わらないので、普通は
- ある回数だけ繰り返す
- ある条件を満たす間だけ繰り返す
- 配列の全要素に対して繰り返す
といった条件をもって繰り返しを行います。
Rubyで繰り返しは、繰り返し専用の構文を使う方法と、メソッドを使う方法があります。
例
最も単純な例で、1から100まで画面に出力するプログラムを考えます。 繰り返しを使わないと、こうなります。
puts 1
puts 2
puts 3
puts 4
# ...
puts 100
これをtimes
メソッドを使って書き換えると次のようになります。
100.times { |count| puts count + 1 }
詳しくはあとで説明します。
別の例として、2.8条件分岐であった消費税計算のプログラムを考えてみます。 このプログラムは不正な値を入力するとメッセージを出力します。 このプログラムを次のように変更してみます。
- コマンドライン引数ではなく標準入力(
gets
)から値段を受取るようにする - 繰り返しを使って正しい値が入力されるまで入力を求めるようにする
loop do
print "税抜価格を入力してください > "
price = gets.to_i
if price <= 0
puts "値段は正の整数で入力してください"
else
puts "税抜価格は#{price}円です。"
puts "税込価格は#{(price * 1.08).to_i}円です。"
break # 繰り返しを抜ける
end
end
これを実行すると次のようになります。
$ ruby loop_tax.rb
税抜価格を入力してください > aaa
値段は正の整数で入力してください
税抜価格を入力してください > 0
値段は正の整数で入力してください
税抜価格を入力してください > -100
値段は正の整数で入力してください
税抜価格を入力してください > 50000
税抜価格は50000円です。
税込価格は54000円です。
構文による繰り返し
while文
while文は繰り返しを行うための専用の構文です。 ある条件を満たしている間だけ繰り返しを行います。
while 条件
処理
end
例えば1〜100を出力するプログラムをwhile
で書くと次のようになります。
count = 1
while count <= 100
puts count
count += 1
end
メソッドによる繰り返し
Rubyでは繰り返しを行うためのメソッドが多くあります。 その中でも代表的な3つのメソッドを紹介します。
メソッドを使うと、次のように繰り返しを書くことができます。
100.times { |count| puts count + 1 }
ブロック
個別のメソッドを紹介する前に、ブロックというものの説明をします。
ブロックとは処理のかたまりのことです。 上の例だと、
{ |count| puts count + 1 }
となっているところがブロックです。 繰り返しを行うメソッドには、繰り返す処理をブロックとして渡します。
ブロックには2種類の書き方があります。
1つ目は{}
で囲う方法です。
オブジェクト.メソッド名(引数...) { |ブロック変数1, 変数2, ...| 処理 }
2つ目はdo〜end
で囲う方法です。処理が複数行に渡る場合はこちらを使います。
オブジェクト.メソッド名(引数...) do |ブロック変数1, 変数2, ...|
処
理
end
ブロック変数とは、ブロックの中で使うことができる変数です。
メソッドによって何が入るかは変わります。
例えばtimes
メソッドの場合は「今が何回目か」という数値が入ります。
ブロック変数が必要ない場合は省略することもできます。
obj.method { 処理 }
obj.method do
処
理
end
timesメソッド
times
は数値オブジェクトのメソッドです。
その数だけ繰り返しを行います。
ブロック変数には「今が何回目の繰り返しか」という数値がはりいます。
数値.times do |変数|
繰り返したい処理
end
times
では0回目から始まります。なので、1〜100を出力するというときは1を足して調整する必要があります。
100.times { |count| puts count + 1 }
eachメソッド
each
は範囲オブジェクトや配列オブジェクトに対して使うことができます。
その要素全てに対して繰り返し処理を行います。
例えば範囲オブジェクトを使って1~100を出力するプログラムは次のようになります。
(1..100).each { |count| puts count }
範囲オブジェクトは1, 2, 3, ..., 100
といった要素を含んでいます。
そしれ、それぞれの要素に対してeach
メソッドでputs
するという処理を繰り返し行っています。
ブロック変数には要素が入ります。
配列のeach
はもう少しわかりやすいです。
例えば、寿司ネタを順番に出力するプログラムは次のようになります。
["サバ", "イワシ", "コハダ"].each do |neta|
puts "#{neta}はとても美味しい!!"
end
[要素1, 要素2, ..., 要素n]
で配列オブジェクトになります。
配列オブジェクトのeach
メソッドを呼ぶことで、全ての要素に対してブロックの処理を実行します。
配列の要素は左から順番に繰り返されます。
これを実行すると次のようになります。
$ ruby each_neta.rb
サバはとても美味しい!!
イワシはとても美味しい!!
コハダはとても美味しい!!
loopメソッド
loop
はKernel
のメソッドで、処理を無限に繰り返します。
実際は無限ループになると困るので、どこかでbreak
などを使って終了する必要があります。
break
についてはあとで説明します。
1から100を出力するプログラムは次のようになります。
count = 1
loop do
puts count
count += 1
# countが100を超えたらbreakで繰り返しを終了する
if count > 100
break
end
end
繰り返し制御
繰り返しはただ繰り返すだけでなく、必要に応じてスキップしたり終了したりできます。
next
next
はnext
以降の繰り返し処理をスキップして、次の回の繰り返し処理に進む命令です。
例えば1から100までのうち、偶数だけ出力したい場合は次のように書きます。
(1..100).each do |count|
# 奇数(2で割り切れない)ときはnextでスキップする
if count % 2 != 0
next
end
puts count
end
break
break
は繰り返しの途中でも強制的に繰り返しを終了させる命令です。
例えば寿司ネタの配列にガリが混ざってるとそこで繰り返しを終了するようなプログラムは次のようになります。
["サバ", "イワシ", "ガリ", "コハダ"].each do |neta|
if neta == "ガリ"
break
end
puts "#{neta}はとても美味しい!!"
end
if
でneta
がガリの場合はbreak
するようにしています。
これを実行するとこうなります。
$ ruby gari.rb
サバはとても美味しい!!
イワシはとても美味しい!!
breakで繰り返しが終了していることがわかります。
練習問題
(1) 1〜100を出力
1〜100を画面に出力するプログラムを次の4通りで作成してください。
while
文times
メソッドeach
メソッドloop
メソッド
(2) 1〜100の偶数を出力
1〜100のうち偶数を画面に出力するプログラムを次の4通りで作成してください。
while
文times
メソッドeach
メソッドloop
メソッド
(3) 1〜100の奇数を出力
1〜100のうち奇数を画面に出力するプログラムを次の4通りで作成してください。
while
文times
メソッドeach
メソッドloop
メソッド
(4) 消費税計算プログラム
2.8条件分岐の練習問題(1)で作成した消費税計算プログラムを次のように変更してください。
- コマンドライン引数ではなく標準入力(
gets
)から値段を受取るようにする loop
メソッドを使って正しい値が入力されるまで入力を求めるようにする