19 Ruby 的迭代器
迭代意味著像迴圈一樣多次執行一次事情,它一個接一個返回陣列或雜湊裡面的元素,本章中會為大家介紹 Ruby 都有哪些迭代器。
1. each
Ruby 的每個迭代器都從雜湊和陣列中返回每個元素,最常見的是 each
迭代器。
下面是一個數組的例子。
例項:
[1, 2, 3, 4, 5].each do |number|
puts number
end
# ---- 輸出結果 ----
1
2
3
4
5
解釋:number 引數代表著每次迭代器迴圈的每個元素,一共迴圈 5 次,分別輸出 1,2,3,4,5。
上面的場景同樣適用於雜湊:
例項:
{a: 1, b: 2, c: 3}.each do |item|
puts "======"
puts item
puts item.class
puts "======"
end
# ---- 輸出結果 ----
======
a
1
Array
======
======
b
2
Array
======
======
c
3
Array
======
解釋:通過上述例子我們可以看到,我們在每次迭代出來的元素是一個Array,第一個元素是每個鍵值對的鍵,第二個元素是每個鍵值對的值。
1.1 each_key 和 each_value
對於雜湊,我們還可以只迭代其值或者鍵。這裡我們有2個方法,一個是each_key
each_value
,它們分別迭代雜湊的所有鍵和所有值:
例項:
{a: '1', b: '2', c: '3', d: '4', e: '5'}.each_key do |key|
puts "key:#{key}"
end
# ---- 輸出結果 ----
key:a class: Symbol
key:b class: Symbol
key:c class: Symbol
key:d class: Symbol
key:e class: Symbol
例項:
{a: '1', b: '2', c: '3', d: '4', e: '5'}.each_value do |value|
puts "value:#{value} class: #{value.class}"
end
# ---- 輸出結果 ----
value:1 class: String
value:2 class: String
value:3 class: String
value:4 class: String
value:5 class: String
2. each_with_index
在 each
的基礎上我們還需要打印出每一個元素對應的索引,這樣我們可以使用each_with_index
。
下面是一個數組的例子。
例項:
[1, 2, 3, 4, 5].each_with_index do |number, index|
puts "index: #{index} \nnumber:#{number}"
end
# ---- 輸出結果 ----
index: 0 number:1
index: 1 number:2
index: 2 number:3
index: 3 number:4
index: 4 number:5
解釋:上述程式碼我們塊中增加了一個index,它代表著每個元素的索引,從0開始依次加1。
下面是一個雜湊的例子:
例項:
{a: '1', b: '2', c: '3', d: '4', e: '5'}.each_with_index do |value, index|
puts "value:#{value} class: #{value.class} index: #{index}"
end
# ---- 輸出結果 ----
value:[:a, "1"] class: Array index: 0
value:[:b, "2"] class: Array index: 1
value:[:c, "3"] class: Array index: 2
value:[:d, "4"] class: Array index: 3
value:[:e, "5"] class: Array index: 4
3. 迭代器的返回值
上面我們講了each
,在Ruby中我們類似each
的迭代器還有很多,比如:map
、collect
、inject
、reject
、select
等,用到這些迭代器的時候,我們主要使用它們的返回值。
讓我們以陣列[1,2,3,4,5,6,7,8,9,10]
舉例:
3.1 each
each
可以把陣列每個元素作為引數執行操作,但返回值仍是陣列本身。
例項:
a = [1,2,3,4,5,6,7,8,9,10].each {|e| puts e.to_s + '!'}
puts a.to_s
# ---- 輸出結果 ----
1!
2!
3!
4!
5!
6!
7!
8!
9!
10!
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
3.2 map
對每個陣列元素執行操作,原始陣列未修改,返回值是修改之後的陣列。
例項:
a = [1,2,3,4,5,6,7,8,9,10].map{|e| e*3 }
puts a.to_s
# ---- 輸出結果 ----
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
3.3 collect
collect
是map
的別名方法,用法同map
。
3.4 inject
取一個累加器(sum
)並更改它的值為與陣列中的元素一樣多的次數。返回累加器的最終值。
例項:
a = [1,2,3,4,5,6,7,8,9,10].inject{|sum,e| sum += e }
puts a
# ---- 輸出結果 ----
55
3.5 reduce
reduce
是inject
的別名,使用方法一樣,不過更多用於遞減操作。
3.6 select
為每個陣列元素執行一個表示式,如果為true
,則將該元素新增到返回的輸出中。在其他語言中,這稱為過濾器。
例項:
a = [1,2,3,4,5,6,7,8,9,10].select{|el| el%2 == 0 }
puts a.to_s
# ---- 輸出結果 ----
[2,4,6,8,10]
3.7 find
取得一個表示式並返回該表示式返回true
的第一個元素:
例項:
a = [1,2,3,4,5,6,7,8,9,10].find{|el| el / 2 == 2 }
puts a.to_s
# ---- 輸出結果 ----
4
3.8 detect
find
的別名,用法和它相同。
3.9 reject
select
的相反方法:為每個陣列元素執行一個表示式,如果表示式為false
,則在輸出中包含該元素。
例項:
a = [1,2,3,4,5,6,7,8,9,10].reject{|e| e==2 || e==8 }
puts a.to_s
# ---- 輸出結果 ----
[1, 3, 4, 5, 6, 7, 9, 10]
4. 次數迭代器
有的時候我們需要進行固定迭代次數的操作,這個時候我們通常有3種方式,使用範圍(Range)、使用times
方法,使用upto
或者downto
方法。
4.1 範圍迭代
使用範圍來固定迭代次數:
例項:
(1..5).each do |i|
puts i
end
# ---- 輸出結果 ----
1
2
3
4
5
解釋:因為 1..5
代表的是從 1~5 的所有數字,所以可以遍歷 5 次。
在進行範圍迭代的時候,我們可以使用step
來選擇每次迭代的步長。
例項:
(0..50).step(5) do |n|
puts n
end
# ---- 輸出結果 ----
0
5
10
15
20
25
30
35
40
45
50
解釋:我們正常使用範圍迭代的時候,都是每次遞增1的,而使用step
,我們可以選擇每次迭代一次遞增5個。
4.2 times 迭代
times
我們在英文中翻譯成次數,Ruby的Integer有一個很通俗易懂的例項方法名字就叫times
,可以讓我們迴圈固定次數。
例項:
5.times.each do |i|
puts i
end
# ---- 輸出結果 ----
0
1
2
3
4
解釋:這裡 5 呼叫了它的times
方法,它可以簡單理解成為建立了一個從 0~4 的陣列。
例項:
5.times.to_a
# ---- 輸出結果 ----
[0, 1, 2, 3, 4]
4.3 upto 和 downto 迭代
這兩個同樣也是 Integer 類的例項方法。
例項:
1.upto(5) do |n|
puts n
end
# ---- 輸出結果 ----
1
2
3
4
5
解釋:通俗的解釋,從1一直迭代到5,和[1, 2, 3, 4 ,5]
陣列同理。
例項:
1.upto(5).to_a
# ---- 輸出結果 ----
[1, 2, 3, 4, 5]
上述是一種遞增迭代的形式,另外一種是遞減的形式。
例項:
5.downto(1) do |n|
puts n
end
# ---- 輸出結果 ----
5
4
3
2
1
**解釋:**會從5一直迭代到1,和 [5, 4, 3, 2, 1]
同理。
例項:
5.upto(1).to_a
# ---- 輸出結果 ----
[5, 4, 3, 2, 1]
5. 小結
本小節中,我們瞭解了迭代類似於迴圈,學習了each
迭代器,each_with_index
迭代器,瞭解了各種迭代器的返回值,以及三種固定次數的迭代器:範圍迭代、times
迭代,upto
和downto
迭代。