更新日:
【Ruby】 for文による繰り返し処理を基礎から応用まで学ぼう
for文は繰り返し処理を行う制御構造のひとつです。inのあとに指定したオブジェクトの要素分だけ処理を繰り返し行います。
for文は、inのあとに指定したオブジェクト
の要素を順番に変数
に代入し、do以下の処理を実行(式
を評価)します。変数に代入するオブジェクトの要素が全て取り出されるまで処理が繰り返されます。
1
2
3
for 変数 in オブジェクト [do]
# 繰り返す処理
end
例えば、以下のコードではary
に格納される配列の要素を順番にbreakfast
に代入し処理が繰り返されるので、ご飯、パン、スムージーの順番で出力されます。
1
2
3
4
5
6
7
8
ary = ['ご飯', 'パン', 'スムージー']
for breakfast in ary do
puts breakfast # 繰り返す処理
end
#=> ご飯
# パン
# スムージー
Rubyの繰り返し処理には、制御構造のwhile,untileやeachメソッドがあります。
今回は、for文の使い方や処理の流れについて学んでいきましょう。
for文の基本的な使い方
この章では、for文の書き方や処理の流れ、どんな場面で使用すれば良いのかなど基本的な部分を解説します。
基本構文
for文は、以下のようにfor~end
が範囲になります。
1
2
3
for 変数 in オブジェクト [do]
# 繰り返す処理
end
上記にあるように、全てのオブジェクトが指定できるわけではないので注意してください。また、変数名は予約語ではなければ自由につけられます。
※doは省略することができます。(この章以降はdoを省略します。)
処理の流れ
記事の冒頭では、for文について下記のように記述しました。
for文は、inのあとに指定したオブジェクトの要素を順番に変数に代入し、式を評価します。変数に代入するオブジェクトの要素が全て取り出されるまで処理が繰り返されます。
この処理の流れをサンプルコードで表すと、以下のような順番になります。
- aryの最初の要素
'ご飯'
をbreakfastに代入される。 - 処理が実行されて
'ご飯'
が出力される。(puts breakfast
) - ①に進んで次の要素
'パン'
がbreakfastに代入される(aryの要素が全て取り出されるまで、①~③が繰り返される)
上記のサンプルコードでは、最後の要素である'スムージー'
がbreakfastに代入されて処理が実行されたらfor文は終了します。
範囲オブジェクトを指定する場合
for文のオブジェクトには、以下のような範囲オブジェクトを指定することができます。
1
2
1 .. 5 # 1以上5以下(5を含む)
1 ... 5 # 1以上5未満(5を含まない)
例えば以下のコードのように範囲オブジェクトを指定することで、処理を決まった回数だけ繰り返すことができます。
1
2
3
4
5
6
7
8
for i in 1..5
puts "#{i}回目です。"
end
#=> 1回目です。
# 2回目です。
# 3回目です。
# 4回目です。
# 5回目です。
オブジェクトは1..5
(1以上5以下)を指定しているので、ループ変数のi
には1, 2, 3, 4, 5の順番で代入されて処理が繰り返されます。puts "#{i}回目です。"
では、式展開を使うことでループ変数を文字列で展開することができています。
複数のループ変数を指定する場合
ループ変数は、カンマ区切りで複数指定することができます。
ハッシュや二次元配列をオブジェクトに指定した場合に使用されることがあります。
1
2
3
for ループ変数1, ループ変数2 in オブジェクト
# 繰り返す処理
end
例えば以下のコードのように指定すると、複数のループ変数(i,j
)には入れ子になった要素をそれぞれ代入することができます。
1
2
3
4
5
6
for i, j in [[1,2], [3,4], [5,6]]
puts "配列の要素は#{i}と#{j}です。"
end
#=> 配列の要素は1と2です。
# 配列の要素は3と4です。
# 配列の要素は5と6です。
上記は、以下の画像のように[1,2]
, [3,4]
, [5,6]
が順番に取り出されて更にその配列の各要素([1,2]
だったら1と2)がループ変数i,j
に代入されます。
次はハッシュを指定する場合をみていきましょう。
ハッシュを指定する場合
for文のオブジェクトには、ハッシュも指定することができます。
ハッシュのキーと値をそれぞれ代入できるようにループ変数を2つ用意します。
1
2
3
for ループ変数1, ループ変数2 in ハッシュ
# 繰り返す処理
end
上記の ループ変数1
にハッシュのキー、ループ変数2
にハッシュの値が代入されます。
例えば以下のコードのようにループ変数key, value
を指定すると、ハッシュから順番に取り出した要素のキーと値を代入することができます。
1
2
3
4
5
6
for key, value in { Apple: 150, Orange: 100, Melon: 600 }
puts "#{key}は#{value}円です。"
end
#=> Appleは150円です。
# Orangeは100円です。
# Melonは600円です。
上記は、以下の画像のようにハッシュの要素を順番に取り出してキーと値をそれぞれループ変数key, value
に代入して処理を繰り返します。
もちろん、以下のコードのようにハッシュを変数に代入することもできます。
1
2
3
4
5
fruits = { Apple: 150, Orange: 100, Melon: 600 }
for key, value in fruits
puts "#{key}は#{value}円です。"
end
eachメソッドとの違いとは?
Rubyの場合は、ハッシュや配列の繰り返し処理にはfor文よりもeachメソッドの方が使用されます。
1
2
3
for 変数 in オブジェクト
# 繰り返す処理
end
上記のfor文は、以下のeachメソッドを使用した場合とほぼ同じ意味です。
1
2
3
オブジェクト.each do |変数|
# 繰り返す処理
end
例えばfor文のサンプルコードをeachメソッドに置き換えた場合は、以下の通りです。
1
2
3
4
5
6
for i in [10, 20, 30]
puts i
end
#=> 10
# 20
# 30
1
2
3
4
5
6
[10, 20, 30].each do | i |
puts i
end
#=> 10
# 20
# 30
eachメソッドでも配列の要素を繰り返し出力することができていますね。
先ほどfor文とeachメソッドはほぼ同じと記述しましたが、この2つの違う点は変数の有効範囲(スコープ)です。
for文の場合は、以下のコードのようにfor文で定義した変数(i
,total
)をfor文の外からでも参照することができます。
1
2
3
4
5
6
7
8
9
for i in [10, 20, 30]
total ||= 0 # totalが存在しなければ0を代入して定義する
total += i
end
total
#=> 60
i
#=> 30
しかし、eachメソッドの場合は変数(i
,total
)のスコープはブロック(do~end
)内になるのでブロック外から参照しようとすると、以下のようにエラーが発生します。
1
2
3
4
5
6
7
8
9
10
[10, 20, 30].each do | i |
total ||= 0
total += i
end
total
#=> NameError (undefined local variable or method `total' for main:Object)
i
#=> NameError (undefined local variable or method `i' for main:Object)
このようにfor文とeachメソッドは同じように繰り返し処理ができますが、変数のスコープが違うということに気をつけてください。
Rubyについてしっかりと学びたい方は、こちらの参考書で理解を深めていきましょう!
for文の応用的な使い方
この章では、基礎から発展したfor文の応用的な使い方や便利な使い方を解説します。
ループの処理をスキップする
next
を使用すると、ループの処理をスキップすることができます。
以下のサンプルコードにnextを使って解説します。
1
2
3
4
5
6
for i in [10, 20, 30]
puts i
end
#=> 10
# 20
# 30
上記のサンプルコードは以下のハイライトのコードのようにnext
を指定することで、ある条件の時にループの処理をスキップすることができます。
1
2
3
4
5
6
for i in [10, 20, 30]
next if i == 10 # iが10だったらループの処理をスキップする
puts i
end
#=> 20
# 30
上記のnext if i == 10
ではi
が10
だったら処理がスキップされるので、次の行のputs i
は実行されず10
は出力されません。
ループの処理をやり直す
redo
を使用すると、ループの処理をやり直すことができます。
例えば以下のハイライトのコードのようにredo
を使用することで、期待する結果ではなかった場合にループの処理をやり直すことができます。
1
2
3
4
5
6
7
8
items = ["名前", "ニックネーム", "年齢"]
puts "あなたの情報を入力してください"
for item in items
print "#{item}は?: "
redo if gets.chomp.empty? #何も入力されなければループ処理をやり直す
end
上記のコードを実行すると、以下の動画のように質問に対して何も入力しなかった場合(if gets.chomp.empty?
)はredo
が実行されて処理が繰り返されます。
※上記の動画では年齢の質問に対して何も入力せずEnter
を押し続けています。
ループを脱出する
break
を使用すると、ループを脱出することができます。
以下のサンプルコードにbreakを使って解説します。
1
2
3
4
5
6
7
8
for i in [10, 20, 30, 40, 50]
puts i
end
#=> 10
# 20
# 30
# 40
# 50
上記のサンプルコードは以下のハイライトのコードのようにbreak
を指定することで、ある条件の時にループを脱出することができます。
1
2
3
4
5
6
7
for i in [10, 20, 30, 40, 50]
break if i == 40 # iが40だったらループを脱出する
puts i
end
#=> 10
# 20
# 30
next
を使用した時はループの次の繰り返しにスキップしていましたが、break
を使用するとそのループ自体から抜けることができます。
制御構造の繰り返し一覧
Rubyの繰り返しは、以下の表の通りです。
繰り返し構文 | 説明 | リンク |
---|---|---|
while | 条件式がtrueの時に繰り返される | whileの使い方 |
until | 条件式がfalseの時に繰り返される | untilの使い方 |
for | オブジェクトの要素分繰り返される | |
break | ループを脱出する | ドキュメントへ |
next | ループの処理をスキップする | ドキュメントへ |
redo | ループの処理をやり直す | ドキュメントへ |
この記事のまとめ
- for文はオブジェクトの要素分だけ処理を繰り返す
- 配列、ハッシュ、範囲オブジェクトがオブジェクトに指定できる
- ブロック内外で変数のスコープは変わらない