連載
» 2014年05月29日 18時00分 UPDATE

若手エンジニア/初心者のためのRuby 2.1入門(4):RubyのRangeクラスと範囲オブジェクト、範囲演算子、イテレーターの使い方 (1/3)

オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。今回は、範囲オブジェクトを扱うRangeや範囲演算子の基本操作、各メソッドの使い方、イテレーターの基礎的な使い方に加え、イテレーターを使う利点などを解説します

[著:麻田優真、監修:山根剛司,株式会社アジャイルウェア]
「若手エンジニア/初心者のためのRuby 2.1入門」のインデックス

連載目次

 前回の「Rubyの配列、ハッシュテーブルを表現するArray、Hashクラスの使い方」では、Rubyにおける基本的な組み込みライブラリとして、配列であるArrayクラスと連想配列であるHashクラスについて解説しました。これらはRubyプログラムでよく使われるデータコンテナーであり、これだけでも書けるプログラムの幅が広がったと思います。

 今回は、前回より引き続き、組み込みライブラリについて理解を深めていきます。今回紹介するのは「Range」と呼ばれるクラスで、数などの範囲を表現するためのものです。また、ArrayやHash、Rangeに深く関わる概念であるイテレーターについても、今回解説します。

※編集部注

本連載はRuby 2.1プログラミングの入門連載です。Ruby on Railsについて学びたい方は連載「開発現場でちゃんと使えるRails 4入門」をご覧ください。


Rangeクラスと範囲オブジェクト、範囲演算子の基本的な使い方

 Rangeクラスのオブジェクトは「範囲オブジェクト」とも呼ばれ、文字通り、数などの範囲を表現するためのオブジェクトです。範囲オブジェクトはfor文や特定のメソッドの引数としてよく使われる他、特定の数などの範囲に対して柔軟に繰り返しを行う場合に使われます。

for文で「範囲オブジェクト」を利用する

 これまでの連載のようにpryを起動して、範囲オブジェクトの使い方を学んでいきましょう。通常、Rangeオブジェクトの生成には範囲演算子「..」もしくは「...」を用います。

[1] pry(main)> 1..5
=> 1..5
[2] pry(main)> 1...5
=> 1...5

 どちらの記法でも範囲オブジェクトが生成されているようですが、これだけではその違いは分かりませんね。

 下記range_01.rbは、範囲オブジェクトをfor文で利用し、範囲演算子「..」「...」の違いを確かめるための例です。ループ変数「i」に範囲オブジェクトから取り出した整数を格納し、それをターミナルに出力しています。

puts ".."
for i in 1..5
  p i
end
puts "..."
for i in 1...5
  p i
end
range_01.rb

..
1
2
3
4
5
...
1
2
3
4
range_01.rbの出力結果

 このように「..」演算子を使うと、終端を含んだ範囲オブジェクトが生成され、「...」演算子を使うと、終端を含まない範囲オブジェクトが生成されます。

補足「for文における範囲オブジェクトとイテレーター」

 ここでfor文で範囲オブジェクトを使う例を紹介しましたが、多くのRubyプログラマーは、今回の後半で紹介する「イテレーター」という概念を使ってループを回すことを好みます。

 上記の例ではループ内で使用しているiという変数がありますが、for文を使ったループの場合、ループの外からも変数iを参照できてしまいます。イテレーターを利用した場合、変数のスコープはブロック内に限定されます。このような理由もあって、Rubyではループにイテレーターを利用した方が安全でしょう。


Range#newを使って範囲オブジェクトを生成する

 一般的には「..」演算子や「...」演算子を使うことで範囲オブジェクトを生成しますが、範囲オブジェクトを生成していることを強調するために、Array.newやHash.newと同様、Rangeクラスのクラスメソッドであるnewを使って範囲オブジェクトを生成することもできます。

[1] pry(main)> Range.new(1, 3)
=> 1..3
[2] pry(main)> Range.new(1, 3, true)
=> 1...3

 newメソッドの第3引数にtrueを指定すると、[2]のように終端を含まない範囲オブジェクトが生成されます。この引数はデフォルトでfalseに設定されているので、省略した場合は[1]のように終端を含む範囲オブジェクトが生成されます。

Range#sizeで範囲オブジェクトに含まれる要素数を取得

 Range#sizeメソッドを用いることで、範囲オブジェクトに含まれる要素数を得ることができます。

[1] pry(main)> (1..5).size
=> 5
[2] pry(main)> (1...5).size
=> 4

 [1]のように、終端を含む範囲オブジェクトの場合は要素数5となっており、[2]のように、終端を含まない範囲オブジェクトの場合の要素数は4になっていることが確認できます。

 また、範囲オブジェクトの始端や終端に無限大を使うことで、無限大の要素数を持つ範囲オブジェクトを生成することもできます。

[3] pry(main)> (1..Float::INFINITY).size
=> Infinity
[4] pry(main)> (-Float::INFINITY..Float::INFINITY).size
=> Infinity

 [3]は1から始まり、正の無限大で終わる範囲オブジェクトを生成し、そのサイズを調べています。「Float::INFINITY」は無限大を表す特別な定数です。1が始端で正の無限大が終端なので、その要素数はInfinity、つまり無限大となります。

 [4]は負の無限大から始まり、正の無限大で終わるような範囲オブジェクトで、[1]と同様、そのサイズは無限大となります。

 この仕組みは、case文で範囲オブジェクトを利用するときに効いてきます。

case文で範囲オブジェクトを利用する

 範囲オブジェクトはfor文で使われる他、case文で利用することもあります。range_02.rbは、コマンドライン引数から任意の整数を取得し、その値に応じて処理を振り分ける例です。

case ARGV[0].to_i
when -Float::INFINITY..-100
  puts "It is -100 or less."
when -99...0
  puts "It is in -99~-1"
when 0
  puts "It is zero."
when 1..99
  puts "It is in 1~99"
when 100..Float::INFINITY
  puts "It is 100 or more."
end
range_02.rb
$ ruby range_02.rb -100000
It is -100 or less.
$ ruby range_02.rb -100
It is -100 or less.
$ ruby range_02.rb -50
It is in -99~-1
$ ruby range_02.rb 0
It is zero.
$ range_02.rb 50
It is in 1~99
$ ruby range_02.rb 100
It is 100 or more.
$ ruby range_02.rb 100000
It is 100 or more.
range_02.rbの実行結果

 このように、whenに続けて範囲オブジェクトを書くことによって処理を振り分けることができます。2行目や10行目で始端や終端が無限大の範囲オブジェクトを活用し、「100以上」や「-100以下」といった条件による振り分けを行っています。

       1|2|3 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。