Ruby Range

Ruby 教學 4 – Ruby Range Object 介紹

在 Ruby range 是一個連續數字或是字母的 object,常用 .. 或是 … 來代表某個範圍,ex: 1..5,代表 1 到 5 之間的每個數字 ( 包含 5 )。

Range 常用在 method 的 argument,或是截取陣列的某一段 elements。

1. 宣告 Range Object

1.1 Range.new

誠如 Ruby 教學 1 – 環境架設及 Ruby 介紹 提到的,Ruby 中幾乎所有東西都是由 object 構成,因此可以直接從 class new 出一個 range instance object。

最後一個 argument default value 是 false,如果改成 true ,會和用 … 宣告 range 的方式一樣,不包含最後一個 element:

ran1 = Range.new(1, 5)
ran2 = Range.new(1, 5, true)

p ran1.class
# Range
p ran2.class
# Range
p ran1
# 1..5
p ran2
# 1...5

1.2 .. 或是 …

可以直接用 .. 或是 … 宣告一個 range object,差別在於:.. 包含結尾的 element,… 則不包含:

ran1 = 1..5
ran2 = 1...5

p ran1.class
# Range
p ran2.class
# Range

2. Range Instance Methods

接著介紹一下在 range 中常用到的 methods:

2.1 range first

.first 會回傳這個 range object 的第一個 element:

ran1 = 1..5
ran2 = 1...5
alpran1 = "a".."e"
alpran2 = "a"..."e"

p ran1.first
# 1
p ran2.first
# 1
p alpran1.first
# "a"
p alpran2.first
# "a"

2.2 range last

.last 則會回傳定義這個 range 的最後一個 element,因此雖然 … 的最後一個 element 不包含在 range object,但用 last method 時仍會回傳這個 element:

ran1 = 1..5
ran2 = 1...5
alpran1 = "a".."e"
alpran2 = "a"..."e"

p ran1.last
# 5
p ran2.last
# 5
p alpran1.last
# "e"
p alpran2.last
# "e"

2.3 range include?

.include? 用來判斷這個 range object 是否包含某 element,會回傳 true or false:

ran1 = 1..5
ran2 = 1...5
alpran1 = "a".."e"
alpran2 = "a"..."e"

p ran1.include?(5)
# true
p ran2.include?(5)
# false
p alpran1.include?("e")
# true
p alpran2.include?("e")
# false

2.4 range size

.size 會回傳這個 range 總共有多少元素,因此 .. 和 … 的 size 回傳的數字會差 1:

.size 只適用在數字的 range,只要 first 或是 last 有一個不是數字,.size 就會回傳 nil
ran1 = 1..5
ran2 = 1...5
alpran1 = "a".."e"
alpran2 = "a"..."e"

p ran1.size
# 5
p ran2.size
# 4
p alpran1.size
# nil
p alpran2.size
# nil

2.5 range each

.each 會遍歷這個 range object 中的所有 element:

alpran1 = "a".."e"
alpran2 = "a"..."e"


alpran1.each { |r| print r }
# abcde
# 寫法等同:
alpran1.each do |r|
  print r
end

alpran2.each { |r| print r }
# abcd

3. 轉換成其他 object

Range 也提供了轉換成其他 object 的 methods:

3.1 range to_a

.to_a 會將 range object 轉換成 array object,但會直接回傳新的 object,而不會變更到原本的 object:

ran1 = 1..5
ran2 = 1...5
alpran1 = "a".."e"
alpran2 = "a"..."e"

p ran1.to_a
# [1, 2, 3, 4, 5]
p ran2.to_a
# [1, 2, 3, 4]
p alpran1.to_a
# ["a", "b", "c", "d", "e"]
p alpran2.to_a
# ["a", "b", "c", "d"]

p ran1
# 1..5

3.2 range to_s

.to_s 會將這個 range 轉成 string object,也會直接回傳新的 object,不會變更到原本的 object:

ran1 = 1..5
ran2 = 1...5
alpran1 = "a".."e"
alpran2 = "a"..."e"

p ran1.to_s
# "1..5"
p ran2.to_s
# "1...5"
p alpran1.to_s
# "a..e"
p alpran2.to_s
# "a...e"

4. Beginless/Endless Range

Beginless/Endless Range 是 2.7.0 版後才有的特殊 range object,簡單來說就是沒有定義 first 或是 last 的 range。

4.1 Beginless Range

沒有定義 first 的 range object:

r = (..4)
p r
# ..4
p Range.new(nil, 4)
# ..4
p Range.new(nil, 4, true)
# ...4

p r.begin
# nil
p r.first
# Error! 因為沒有定義 first,所以會有 error
p r.include?(-50)
# true
p r.include?(4)
# true

可以用來截取 array 的某一段:

arr = [1, 2, 3, 4]
range = (..2)
p arr[range]
# [1, 2, 3]

4.2 Endless Range

沒有定義 last 的 range object:

r = (1..)
p r
# 1..
p Range.new(1, nil)
# 1..
p Range.new(1, nil, true)
# 1...

p r.end
# nil
p r.last
# Error! 因為沒有定義 first,所以會有 error
p r.include?(-50)
# false
p r.include?(4)
# true

也可以用來截取陣列:

arr = [1, 2, 3, 4]
range = (1..)
p arr[range]
# [2, 3, 4]

5. 參考資料

Learn to Code with Ruby
Class: Range (Ruby 3.1.2)

如果覺得我的文章有幫助的話,歡迎幫我的粉專按讚哦~謝謝你!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top