ruby は日本人のまつもとゆきひろ(Matz)氏によって開発された言語です。「enjoy programing」を思想としており、
開発者ができるだけストレスなくプログラミングできるように設計されています。
ruby言語には他のプログラミング言語では当たり前のループ制御構造である「for文」や「while文」も存在しますが、オブジェクトのメソッドを使っての様々なループができるという特徴があります。
この記事ではruby初心者、またはrubyをこれから勉強しようと考えている方を対象としてこのオブジェクトのループ処理について解説したいと思います。
1. times
rubyは全てがオブジェクトで構成される純粋オブジェクト指向言語です。そのため「3」という数字や「”hello”」という文字列もオブジェクトとして認識されます。
オブジェクトであるので「3」という数字自体もメソッドを持つことが可能です。そのメソッドの1つに「times」メソッドがあります。
3.times do
puts 'Hello World'
end
# Hello World
# Hello World
# Hello World
上記のプログラムは「3回繰り返す」というループです。とても直感的で分かりやすいループになっていると思います。
ループの中で「今が何回目のループなのか」を捕捉したい時がありますよね。その場合は下記のように書くことでループの回数を取得可能です。
3.times do |i|
puts (i+1).to_s + '回目の Hello World'
end
# 1回目の Hello World
# 2回目の Hello World
# 3回目の Hello World
2. step
timesメソッドは直感的ですが、整数型でしか使えないという欠点があります。そこで基本的な数値型であれば使えるメソッドとしてstepがあります。
stepは始まりの数字と終わりの数字を指定すること、その数字に至るまでループを繰り返すというものです。
「(この数字から).step(この数字を越えるまで)」というループになります。
1.step(3) do
puts 'Hello World'
end
# Hello World
# Hello World
# Hello World
前述したようにこのメソッドは数値型であれば基本的に使用可能です。例えばFloat型でも使えます。
1.1.step(3) do
puts 'Hello World'
end
# Hello World
# Hello World
上記の例では2回しか表示されませんでした。これは「1回のループで繰り上がる値」がデフォルトでは「1」と設定されているからです。
「1.1から始まり3を越えるまで繰り返す(ただし1回のループが終わるたびに足される数値は1)」というループになっているということです。
そしてこの「1回のループが終わるたびに足される数値」をstepメソッドの第2引数で指定することができます。試しにこの数値を「0.5」にしてみます。
すると1回のループで足される値が0.5になったので4回ループが実行されるようになります。
1.1.step(3, 0.5) do
puts 'Hello World'
end
# Hello World
# Hello World
# Hello World
# Hello World
この「1回のループが終わるたびに足される数値」は応用が利き、例えばこの値を負の値にすることで「5から1まで」というようなデクリメントのループも可能となります。
5.step(1, -1) do |i|
puts i.to_s + '回目の Hello World'
end
# 5回目の Hello World
# 4回目の Hello World
# 3回目の Hello World
# 2回目の Hello World
# 1回目の Hello World
3. upto
uptoはInteger型限定のメソッドです。Integer型限定で「1回のループが終わるたびに足される数値」が「1」で固定されているstepメソッドであると考えることができます。
1.upto(3) do
puts 'Hello World'
end
# Hello World
# Hello World
# Hello World
「stepで必要十分ではないか?」と言われると確かにそうなのですが、使い方が限定されている方が読み手にとっても意図が明確に伝わるものです。
下記の例のように変数で使うような場合、uptoメソッドを使うということは「その変数にはinteger型が来ることを期待している」ということがすぐにわかります。
また、「1回のループが終わるたびに足される数値」が「1」であることも確定し、他の実装者が好き勝手変更することもできないのでバグりにくいプログラムになります。
hoge = 4;
// hogeにはinteger型が期待される。step数は1であることが確定している
hoge.upto(6) do
puts 'hoge'
end
# hoge
# hoge
# hoge
4. downto
downtoはInteger型限定のメソッドです。Integer型限定で「1回のループが終わるたびに足される数値」が「-1」で固定されているstepメソッドであると考えることができます。利点や存在意義はuptoと同じです。使い方が限定され得るので意図が明確になります。
3.downto(1) do |i|
puts i.to_s + '回目の Hello World'
end
# 3回目の Hello World
# 2回目の Hello World
# 1回目の Hello World
4. each
eachメソッドはそれ自身が持つ各値の数だけループを繰り返すものです。このメソッドはここまで見てきたinteger型やstring型のクラスは持っていません。もっとも直感的にわかるものでいうとarray型のオブジェクトだと思います。
下記は配列内の各変数をeachメソッドを使って表示する例です。
["a", "b", "c", "d", "e"].each do |item|
puts item
end
# a
# b
# c
# d
# e
arrayクラスと同様にrangeクラスもeachメソッドを持っているため、値の数だけの繰り返しを実行できます。
rangeクラスというものは範囲オブジェクトと呼ばれ、「値「A」から値「B」まで」という条件でオブジェクトを作るものです。
例えば「1から5まで」と指定すればrangeオブジェクトは「1,2,3,4,5」の値を保持することになります。
(1..5).each do |item|
puts item
end
# 1
# 2
# 3
# 4
# 5
まとめ
この記事ではrubyにおけるオブジェクトのループ処理について解説しました。今までプログラミングをやってきた方としてはfor文やwhile文は慣れ親しんだものとして受け入れやすいかもしれません。
しかし、rubyのtimesメソッドやdowntoメソッドを使うことによって今までよりも直感的で意図が明確に伝わりやすい素晴らしいループが書けると思います。rubyを使う際にはこれらのメソッドを積極的に使うと良いでしょう。