要約
範囲オブジェクトのクラス。範囲オブジェクトは文字どおり何らかの意味での範囲を表します。数の範囲はもちろん、日付の範囲や、「"a" から "z" まで」といった文字列の範囲を表すこともできます。
作り方
範囲オブジェクトは、Range.new を用いるほか、範囲演算子(`..' または `...')を用いた 演算子式/範囲式 で生成できます。いずれの方法でも始端と終端を与えます。
Range.new(1, 5) # 1 以上 5 以下
1..5 # 同上
1...5 # 1 以上 5 未満
この例で分かるように、範囲オブジェクトは終端を含む範囲も含まない範囲も表せます。
Ruby 2.6.0 からは、終端に nil を与えることで「終端を持たない範囲オブジェクト」を作ることができるようになりました。
p Range.new(1, nil) # 1 以上(上限無し)を表す
p(1..nil) # 同上
p(1..) # 同上(略した書き方)
機能
範囲オブジェクトは範囲を表しているので、基本的な機能として「ある値がその範囲に含まれるか否かを判定する」ということがあります。
p (1..5).cover?(6) # => false
p (1..5).cover?(5) # => true
p (1...5).cover?(5) # => false
Range#cover? メソッドでの判定には演算子 <=> が使われます。
当然、始端と終端は <=> メソッドで比較可能である(nil 以外を返す)必要があります。
範囲オブジェクトのもう一つの基本的機能は繰り返しの範囲を表すことです。
(3..5).each{ |i| p i }
# => 3
# 4
# 5
(3...5).each{ |i| p i }
# => 3
# 4
繰り返しの範囲を表す範囲オブジェクトは、始端が「次の値」を返す succ メソッドを持たなければなりません。
Range クラスには Enumerable が include してあるので,Range#each に基づき、Enumerable モジュールが提供する多様なメソッドを使うことができます。
破壊的な変更
Ruby の Range クラスは immutable です。つまり、オブジェクト自体を破壊的に変更することはできません。ですので、一度生成された Range のオブジェクトの指し示す範囲は決して変更することはできません。
range = 1..10
range.first # => 1
range.first = 1 # => NoMethodError
目次
- 特異メソッド
- インスタンスメソッド
継承しているメソッド
- Enumerableから継承しているメソッド
-
- all?
- any?
- chain
- chunk
- chunk_while
- collect
- collect_concat
- count
- cycle
- detect
- drop
- drop_while
- each_cons
- each_entry
- each_slice
- each_with_index
- each_with_object
- entries
- filter
- find
- find_all
- find_index
- flat_map
- grep
- grep_v
- group_by
- inject
- lazy
- map
- max_by
- min_by
- minmax
- minmax_by
- none?
- one?
- partition
- reduce
- reject
- reverse_each
- select
- slice_after
- slice_before
- slice_when
- sort
- sort_by
- sum
- take
- take_while
- to_a
- to_h
- uniq
- zip
特異メソッド
new(first, last, exclude_end = false) -> Range
[permalink][rdoc][edit]-
first から last までの範囲オブジェクトを生成して返します。
exclude_end が真ならば終端を含まない範囲オブジェクトを生成します。exclude_end 省略時には終端を含みます。
- [PARAM] first:
- 最初のオブジェクト
- [PARAM] last:
- 最後のオブジェクト
- [PARAM] exclude_end:
- 真をセットした場合終端を含まない範囲オブジェクトを生成します
- [EXCEPTION] ArgumentError:
- first <=> last が nil の場合に発生します
Range.new(1, 10) # => 1..10 Range.new(1, 10, true) # => 1...10
require 'date' Range.new(Date.today, Date.today >> 1).each {|d| puts d } # => 2017-09-16 # 2017-09-17 # ... # 2017-10-16
require 'ipaddr' Range.new(IPAddr.new("192.0.2.1"), IPAddr.new("192.0.2.3")).each {|ip| puts ip} # => 192.0.2.1 # 192.0.2.2 # 192.0.2.3
MyInteger = Struct.new(:value) do def succ self.class.new(value + 1) end def <=>(other) value <=> other.value end def to_s value.to_s end end Range.new(MyInteger.new(1), MyInteger.new(3)).each {|i| puts i } # => 1 # 2 # 3
インスタンスメソッド
step(s = 1) {|item| ... } -> self
[permalink][rdoc][edit]step(s = 1) -> Enumerator
step(s = 1) -> Enumerator::ArithmeticSequence
self % s -> Enumerator
self % s -> Enumerator::ArithmeticSequence
-
範囲内の要素を s おきに繰り返します。
- [PARAM] s:
- 各ステップの大きさを数値で指定します。負の数を指定することもできます。
- [RETURN]
- ブロックを指定した時は self を返します。
- [RETURN]
- ブロックを指定しなかった時かつ数値の Range の時は Enumerator::ArithmeticSequence を返します。
- [RETURN]
- ブロックを指定しなかったその他の Range の時は Enumerator を返します。(例: String の Range)
("a" .. "f").step(2) {|v| p v} # => "a" # "c" # "e"
self == other -> bool
[permalink][rdoc][edit]-
指定された other が Range クラスのインスタンスであり、始端と終端が == メソッドで比較して等しく、Range#exclude_end? が同じ場合に true を返します。そうでない場合に false を返します。
- [PARAM] other:
- 自身と比較したいオブジェクトを指定します。
p (1..2) == (1..2) # => true p (1..2) == (1...2) # => false p (1..2) == Range.new(1.0, 2.0) # => true
self === obj -> bool
[permalink][rdoc][edit]cover?(obj) -> bool
-
obj が範囲内に含まれている時に真を返します。
Range#=== は主に case 式での比較に用いられます。
Range#include? と異なり <=> メソッドによる演算により範囲内かどうかを判定します。 Range#include? は原則として離散値を扱い、 Range#cover? は連続値を扱います。(数値については、例外として Range#include? も連続的に扱います。)
Range#exclude_end?がfalseなら「begin <= obj <= end」を、 trueなら「begin <= obj < end」を意味します。
引数がRangeオブジェクトの場合、引数の範囲がselfの範囲に含まれる時にtrueを返します。
「(a..b).cover?(c...d)」のように終端を含まないRangeオブジェクトが引数に渡されており、「a <= c && b < d」を満たし、cが数値ではない(つまり引数のRangeの終端を求めるためにsuccメソッドの呼び出しが必要な)場合、パフォーマンスの問題が起きる可能性があります。
p ('aaaaa'..'zzzzy').cover?('aaaaa'...'zzzzz') # => true
- [PARAM] obj:
- 比較対象のオブジェクトを指定します。
(1.1..2.3).include?(1.0) # => false (1.1..2.3).include?(1.1) # => true (1.1..2.3).include?(1.555) # => true (1.1..2.3).cover?(1.0) # => false (1.1..2.3).cover?(1.1) # => true (1.1..2.3).cover?(1.555) # => true
('b'..'d').include?('d') # => true ('b'..'d').include?('ba') # => false ('b'..'d').cover?('d') # => true ('b'..'d').cover?('ba') # => true
(Date.new(2014,1,3)..Date.new(2014,1,5)).include?(Date.new(2014,1,5)) # => true (Time.new(2014,1,3)..Time.new(2014,1,5)).include?(Time.new(2014,1,4,10,10,10)) # => true (Date.new(2014,1,3)..Date.new(2014,1,5)).cover?(Date.new(2014,1,5)) # => true (Time.new(2014,1,3)..Time.new(2014,1,5)).cover?(Time.new(2014,1,4,10,10,10)) # => true
(1..5).cover?(2..3) #=> true (1..5).cover?(0..6) #=> false (1..5).cover?(1...6) #=> true
[SEE_ALSO] 制御構造/case
[SEE_ALSO] Range#include?
begin -> object
[permalink][rdoc][edit]first -> object
-
始端の要素を返します。範囲オブジェクトが始端を含むかどうかは関係ありません。
p (1..5).begin # => 1 p (1..0).begin # => 1
[SEE_ALSO] Range#end
first(n) -> [object]
[permalink][rdoc][edit]-
最初の n 要素を返します。範囲内に要素が含まれない場合は空の配列を返します。
- [PARAM] n:
- 取得する要素数を整数で指定します。整数以外のオブジェクトを指定した場合は to_int メソッドによる暗黙の型変換を試みます。
- [EXCEPTION] TypeError:
- 引数に整数以外の(暗黙の型変換が行えない)オブジェクトを指定した場合に発生します。
- [EXCEPTION] ArgumentError:
- n に負の数を指定した場合に発生します。
(10..20).first(3) # => [10, 11, 12]
[SEE_ALSO] Range#last, [ruby-core:12697]
bsearch {|obj| ... } -> object | nil
[permalink][rdoc][edit]bsearch -> Enumerator
-
ブロックの評価結果で範囲内の各要素の大小判定を行い、条件を満たす値を二分探索(計算量は O(log n))で検索します。要素が見つからない場合は nil を返します。
本メソッドはブロックを評価した結果により以下のいずれかのモードで動作します。
- find-minimum モード
- find-any モード
find-minimum モード(特に理由がない限りはこのモードを使う方がいいでしょう)では、条件判定の結果を以下のようにする必要があります。
- 求める値がブロックパラメータの値か前の要素の場合: true を返す
- 求める値がブロックパラメータより後の要素の場合: false を返す
ブロックの評価結果が true になる最初の要素を返すか、nil を返します。
ary = [0, 4, 7, 10, 12] (0...ary.size).bsearch {|i| ary[i] >= 4 } # => 1 (0...ary.size).bsearch {|i| ary[i] >= 6 } # => 2 (0...ary.size).bsearch {|i| ary[i] >= 8 } # => 3 (0...ary.size).bsearch {|i| ary[i] >= 100 } # => nil (0.0...Float::INFINITY).bsearch {|x| Math.log(x) >= 0 } # => 1.0
find-any モードは bsearch(3) のように動作します。ブロックは真偽値ではなく、以下のような数値を返す必要があります。求める値の範囲がx...y (x <= y)であるとします。また、ブロックパラメータの値を v とします。
- ブロックパラメータの値が求める値の範囲よりも小さい(v < x)場合: 正の数を返す
- ブロックパラメータの値が求める値の範囲に合致する(x <= v < y)場合: 0 を返す
- ブロックパラメータの値が求める値の範囲よりも大きい(y <= v)場合: 負の数を返す
ブロックの評価結果が 0 になるいずれかの要素を返すか、nil を返します。
ary = [0, 100, 100, 100, 200] (0..4).bsearch {|i| 100 - ary[i] } # => 1, 2 or 3 (0..4).bsearch {|i| 300 - ary[i] } # => nil (0..4).bsearch {|i| 50 - ary[i] } # => nil
上記の 2 つのモードを混在して使用しないでください(ブロックの評価結果は常に true/false、数値のいずれかを一貫して返すようにしてください)。また、二分探索の各イテレーションで値がどのような順序で選ばれるかは未規定です。
ブロックが与えられなかった場合は、 Enumerator のインスタンスを返します。
- [EXCEPTION] TypeError:
- ブロックの評価結果が true、false、nil、数値以外であった場合に発生します。
[SEE_ALSO] Array#bsearch
each {|item| ... } -> self
[permalink][rdoc][edit]each -> Enumerator
-
範囲内の要素に対して繰り返します。
Range#each は各要素の succ メソッドを使用してイテレーションするようになりました。
- [EXCEPTION] TypeError:
- succ メソッドを持たないクラスの範囲オブジェクトに対してこのメソッドを呼んだ場合に発生します。
(10..15).each {|n| print n, ' ' } # prints: 10 11 12 13 14 15 (2.5..5).each {|n| print n, ' ' } # raises: TypeError: can't iterate from Float
end -> object
[permalink][rdoc][edit]last -> object
-
終端の要素を返します。範囲オブジェクトが終端を含むかどうかは関係ありません。
(10..20).last # => 20 (10...20).last # => 20
[SEE_ALSO] Range#begin
last(n) -> [object]
[permalink][rdoc][edit]-
最後の n 要素を返します。範囲内に要素が含まれない場合は空の配列を返します。
- [PARAM] n:
- 取得する要素数を整数で指定します。整数以外のオブジェクトを指定した場合は to_int メソッドによる暗黙の型変換を試みます。
- [EXCEPTION] TypeError:
- 引数に整数以外の(暗黙の型変換が行えない)オブジェクトを指定した場合に発生します。
- [EXCEPTION] ArgumentError:
- n に負の数を指定した場合に発生します。
[注意] 引数を省略して実行した場合は、終端を含むかどうか (Range#exclude_end? の戻り値)に関わらず終端の要素を返す事に注意してください。
(10..20).last(3) # => [18, 19, 20] (10...20).last(3) # => [17, 18, 19]
[SEE_ALSO] Range#first
eql?(other) -> bool
[permalink][rdoc][edit]-
指定された other が Range クラスのインスタンスであり、始端と終端が eql? メソッドで比較して等しく、Range#exclude_end? が同じ場合に true を返します。そうでない場合に false を返します。
- [PARAM] other:
- 自身と比較したいオブジェクトを指定します。
p (1..2).eql?(1..2) # => true p (1..2).eql?(1...2) # => false p (1..2).eql?(Range.new(1.0, 2.0)) # => false
exclude_end? -> bool
[permalink][rdoc][edit]-
範囲オブジェクトが終端を含まないとき真を返します。
(1..5).exclude_end? # => false (1...5).exclude_end? # => true
hash -> Integer
[permalink][rdoc][edit]-
始端と終端のハッシュ値と Range#exclude_end? の値からハッシュ値を計算して整数として返します。
p (1..2).hash # => 5646 p (1...2).hash # => 16782863
include?(obj) -> bool
[permalink][rdoc][edit]member?(obj) -> bool
-
obj が範囲内に含まれている時に真を返します。
<=> メソッドによる演算により範囲内かどうかを判定するには Range#cover? を使用してください。
- [PARAM] obj:
- 比較対象のオブジェクトを指定します。
p (0.1 .. 0.2).member?(0.15) # => true # 文字列の場合、include? は辞書順の比較になる p ("a" .. "c").include?("ba") # => false p ("a" .. "c").member?("ba") # => false
[SEE_ALSO] 制御構造/case
[SEE_ALSO] Range#cover?
inspect -> String
[permalink][rdoc][edit]-
self を文字列に変換します(始端と終端のオブジェクトは #inspect メソッドで文字列に変換されます)。
[SEE_ALSO] Range#to_s
(1..5).inspect # => "1..5" ("1".."5").inspect # => "\"1\"..\"5\""
max -> object | nil
[permalink][rdoc][edit]max(n) -> [object]
-
範囲内の最大の値、もしくは最大の n 要素を返します。
- [PARAM] n:
- 取得する要素数。
(1..5).max # => 5
(1..5).max(3) # => [5, 4, 3]
始端が終端より大きい場合、もしくは、終端を含まない範囲オブジェクトの始端が終端と等しい場合は、引数を指定しない形式では nil を返します。引数を指定する形式では、空の配列を返します。
(2..1).max # => nil (1...1).max # => nil
(2..1).max(3) # => [] (1...1).max(3) # => []
max {|a, b| ... } -> object | nil
[permalink][rdoc][edit]max(n) {|a, b| ... } -> [object]
-
ブロックの評価結果で範囲内の各要素の大小判定を行い、最大の要素、もしくは最大の n 要素を返します。引数を指定しない形式では、範囲内に要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。
ブロックの値は、a > b のとき正、 a == b のとき 0、a < b のとき負の整数を、期待しています。
- [PARAM] n:
- 取得する要素数。
- [EXCEPTION] TypeError:
- ブロックが整数以外を返したときに発生します。
[SEE_ALSO] Range#last, Range#min, Enumerable#max
h = { 1 => "C", 2 => "Go", 3 => "Ruby" } (1..3).max { |a, b| h[a].length <=> h[b].length } # => 3
(1..3).max(2) { |a, b| h[a].length <=> h[b].length } # => [3, 2]
min -> object | nil
[permalink][rdoc][edit]min(n) -> [object]
-
範囲内の最小の値、もしくは最小の n 要素を返します。
- [PARAM] n:
- 取得する要素数。
(1..5).min # => 1
(1..5).min(3) # => [1, 2, 3]
始端が終端より大きい場合、もしくは、終端を含まない範囲オブジェクトの始端が終端と等しい場合は、引数を指定しない形式では nil を返します。引数を指定する形式では、空の配列を返します。
(2..1).min # => nil (1...1).min # => nil
(2..1).min(3) # => [] (1...1).min(3) # => []
min {|a, b| ... } -> object | nil
[permalink][rdoc][edit]min(n) {|a, b| ... } -> [object]
-
ブロックの評価結果で範囲内の各要素の大小判定を行い、最小の要素、もしくは最小の n 要素を返します。引数を指定しない形式では、範囲内に要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。
ブロックの値は、a > b のとき正、a == b のとき 0、 a < b のとき負の整数を、期待しています。
- [PARAM] n:
- 取得する要素数。
- [EXCEPTION] TypeError:
- ブロックが整数以外を返したときに発生します。
[SEE_ALSO] Range#first, Range#max, Enumerable#min
h = { 1 => "C", 2 => "Go", 3 => "Ruby" } (1..3).min { |a, b| h[a].length <=> h[b].length } # => 1
(1..3).min(2) { |a, b| h[a].length <=> h[b].length } # => [1, 2]
size -> Integer | Float::INFINITY | nil
[permalink][rdoc][edit]-
範囲内の要素数を返します。始端、終端のいずれかのオブジェクトが Numeric のサブクラスのオブジェクトではない場合には nil を返します。
(10..20).size # => 11 ("a".."z").size # => nil (-Float::INFINITY..Float::INFINITY).size # => Infinity
to_s -> String
[permalink][rdoc][edit]-
self を文字列に変換します(始端と終端のオブジェクトは #to_s メソッドで文字列に変換されます)。
[SEE_ALSO] Range#inspect
(1..5).to_s # => "1..5" ("1".."5").to_s # => "1..5"