LoginSignup
8
6

More than 5 years have passed since last update.

Range オブジェクトの exclude_end? (ドット3つ表記) について

Posted at

(1..9) と (1...10)

Ruby で Range オブジェクトを作成する場合によく使われる記法として (開始)..(終了) って表現があります。そして忘れがちですが (開始)...(終了) といったドット3つの初期化方法もあります。

(1..9)   # 1..9
(1...10) # 1...10

そして、上記の 1..91...10 の 2つのオブジェクトは、意味的には同じように感じますが比較すると false を返します。

(1..9).to_a == (1...10).to_a # true
(1..9) == (1...10)           # false

上記は厳密に違う意味があるオブジェクトで、具体的には exclude_end? ってフラグを持ってます。これは Range.new の第三引数でも指定出来ます。

Range.new(1, 9)        # 1..9
Range.new(1, 9, false) # 1..9
Range.new(1, 9, true)  # 1...9
(1..9).exclude_end?    # false
(1...10).exclude_end?  # true

usecase

Range を作るとき、end 側の指定で hoge - 1 みたいにわざわざ 1つ減算して与えるくらいならば、
ドット3つ付けて exclude_end な Range を作るとシンプルな記述になる場合があります。

n = 4
s = "hogehoge"

puts s[0..(n-1)] # こっちより...
puts s[0...n]    # こっちの方が意図が伝わりやすい(か?)
require 'date'
d = Date.new(2013, 4)

# 翌月1日を含まない範囲、すなわち当月の範囲の日付配列
(d...(d >> 1)).map(&:to_s)
# => [ "2013-04-01","2013-04-02","2013-04-03",..."2013-04-30"]

ActiveRecord で範囲を指定する際にも終端を含めない条件を生成できます。

Table.where(id: (1..10)).to_sql
# {途中省略} FROM `tables` WHERE `tables`.`id` BETWEEN 1 AND 10
Table.where(id: (1...10)).to_sql
# {途中省略} FROM `tables`  WHERE (`tables`.`id` >= 1 AND `tables`.`id` < 10)
8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6