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
迭代。