すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Ruby

【Ruby】 for文による繰り返し処理を基礎から応用まで学ぼう

ぴっかちゃん
ぴっかちゃん

for文は繰り返し処理を行う制御構造のひとつです。inのあとに指定したオブジェクトの要素分だけ処理を繰り返し行います。

for文は、inのあとに指定したオブジェクトの要素を順番に変数に代入し、do以下の処理を実行(を評価)します。変数に代入するオブジェクトの要素が全て取り出されるまで処理が繰り返されます。

for文の文法
1
2
3
for 変数 in オブジェクト [do]
# 繰り返す処理 end

例えば、以下のコードではaryに格納される配列の要素を順番にbreakfastに代入し処理が繰り返されるので、ご飯、パン、スムージーの順番で出力されます。

breakfast.rb | for文のサンプルコード
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が範囲になります。

for文の文法
1
2
3
for 変数 in オブジェクト [do]
  # 繰り返す処理
end
  • 変数(ループ変数) - オブジェクトの各要素を代入する変数を記述します。
  • オブジェクト - 配列ハッシュ、範囲オブジェクトが指定できます。
  • 繰り返す処理 - 繰り返したい処理を記述します。

上記にあるように、全てのオブジェクトが指定できるわけではないので注意してください。また、変数名は予約語ではなければ自由につけられます。

※doは省略することができます。(この章以降はdoを省略します。)

処理の流れ

記事の冒頭では、for文について下記のように記述しました。

for文は、inのあとに指定したオブジェクトの要素を順番に変数に代入し、式を評価します。変数に代入するオブジェクトの要素が全て取り出されるまで処理が繰り返されます。

この処理の流れをサンプルコードで表すと、以下のような順番になります。

for文の処理の流れ

  1. aryの最初の要素'ご飯'をbreakfastに代入される。
  2. 処理が実行されて'ご飯'が出力される。(puts breakfast)
  3. ①に進んで次の要素'パン'がbreakfastに代入される(aryの要素が全て取り出されるまで、①~③が繰り返される)

上記のサンプルコードでは、最後の要素である'スムージー'がbreakfastに代入されて処理が実行されたらfor文は終了します。

ポイント

for文は、オブジェクトの要素が全て取り出されるまで繰り返し処理が行われる

範囲オブジェクトを指定する場合

for文のオブジェクトには、以下のような範囲オブジェクトを指定することができます。

範囲オブジェクトのサンプル
1
2
1 .. 5 # 1以上5以下(5を含む)
1 ... 5 # 1以上5未満(5を含まない)

例えば以下のコードのように範囲オブジェクトを指定することで、処理を決まった回数だけ繰り返すことができます。

sample.rb | 範囲オブジェクトを指定する場合
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}回目です。"では、式展開を使うことでループ変数を文字列で展開することができています。

複数のループ変数を指定する場合

ループ変数は、カンマ区切りで複数指定することができます。
ハッシュや二次元配列をオブジェクトに指定した場合に使用されることがあります。

for文の文法(ループ変数を複数指定する場合)
1
2
3
for ループ変数1, ループ変数2 in オブジェクト
# 繰り返す処理 end

例えば以下のコードのように指定すると、複数のループ変数(i,j)には入れ子になった要素をそれぞれ代入することができます。

sample.rb | ループ変数を複数指定した場合
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を指定すると、ハッシュから順番に取り出した要素のキーと値を代入することができます。

fruits.rb | ハッシュを指定する場合
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に代入して処理を繰り返します。

ハッシュとループ変数の関係

もちろん、以下のコードのようにハッシュを変数に代入することもできます。

fruits.rb | ハッシュを変数に代入した場合
1
2
3
4
5
fruits = { Apple: 150, Orange: 100, Melon: 600 }
for key, value in fruits
puts "#{key}#{value}円です。" end
ポイント

for文のオブジェクトにハッシュを指定する場合は、キーと値を代入できるようにループ変数は2つ用意しましょう。

eachメソッドとの違いとは?

Rubyの場合は、ハッシュや配列の繰り返し処理にはfor文よりもeachメソッドの方が使用されます。

for文の文法
1
2
3
for 変数 in オブジェクト
  # 繰り返す処理
end

上記のfor文は、以下のeachメソッドを使用した場合とほぼ同じ意味です。

eachメソッドの文法
1
2
3
オブジェクト.each do |変数|
  # 繰り返す処理
end

例えばfor文のサンプルコードをeachメソッドに置き換えた場合は、以下の通りです。

sample.rb | for文のサンプルコード
1
2
3
4
5
6
for i in [10, 20, 30]
  puts i
end
#=> 10
#   20
#   30
sample.rb | eachメソッドに置き換えた場合
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文の外からでも参照することができます。

sample.rb | 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)内になるのでブロック外から参照しようとすると、以下のようにエラーが発生します。

sample.rb | 変数をブロック外から参照した場合
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メソッドは同じように繰り返し処理ができますが、変数のスコープが違うということに気をつけてください。

ポイント
  1. 変数の使用できる範囲(有効範囲)を「変数のスコープ」と呼びます。
  2. for文はブロック内外で変数のスコープは変わりません。(外から参照できる)
  3. eachメソッドはブロック内外で変数のスコープが変わります。(外から参照できない)
ぴっかちゃん

Rubyについてしっかりと学びたい方は、こちらの参考書で理解を深めていきましょう!

for文の応用的な使い方

この章では、基礎から発展したfor文の応用的な使い方や便利な使い方を解説します。

ループの処理をスキップする

nextを使用すると、ループの処理をスキップすることができます。

以下のサンプルコードにnextを使って解説します。

sample.rb | for文のサンプルコード
1
2
3
4
5
6
for i in [10, 20, 30]
  puts i
end
#=> 10
#   20
#   30

上記のサンプルコードは以下のハイライトのコードのようにnextを指定することで、ある条件の時にループの処理をスキップすることができます。

sample.rb | 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ではi10だったら処理がスキップされるので、次の行のputs iは実行されず10は出力されません。

ループの処理をやり直す

redoを使用すると、ループの処理をやり直すことができます。

例えば以下のハイライトのコードのようにredoを使用することで、期待する結果ではなかった場合にループの処理をやり直すことができます。

sample.rb | 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が実行されて処理が繰り返されます。

redoを使用した場合

※上記の動画では年齢の質問に対して何も入力せずEnterを押し続けています。

ループを脱出する

breakを使用すると、ループを脱出することができます。

以下のサンプルコードにbreakを使って解説します。

sample.rb | for文のサンプルコード
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を指定することで、ある条件の時にループを脱出することができます。

sample.rb | 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文はオブジェクトの要素分だけ処理を繰り返す
  • 配列、ハッシュ、範囲オブジェクトがオブジェクトに指定できる
  • ブロック内外で変数のスコープは変わらない