今天要讲的是迭代器(iterator)。什么是迭代器呢?它的好处就是会一个一个地传回集合里的元素,让咱们能够利用迭代方法作重复的事。面试
在Ruby里的collection集合里有Array数组和Hash哈希。数组
今天要介绍三种用在collection集合的迭代器分别叫each,map和collect,这也是常见的Ruby面试考题呢!.net
Ruby经典面试题目#14索引
Day14 each,map和collect比较?What's the difference between each,map and collect?element
咱们来使用这三种迭代器,在Array和Hash两种集合中各举几个生活化的例子,相信你们就比较容易暸解啰!get
Arrayhash
Array#eachit
最近我在进行旅行存钱计划。我有三个银行账户,NAB,CAN,和WESTPAC,开户金额分别为100,200,300。因此我写一个数组集合放入初始金额[100,200,300]。io
假设我打算开始从本周开始在每一个账户存入50元(+50),能够在数组后加上.each方法:进阶
[100,200,300].each {|n| puts n+50}
结果列出各个账户的金额(注意:puts写在block大括号里):
150
250
350
通过.each方法做用以后,只会分别印出同一数组中各个元素的值,不会产生新数组。
Array#collect
以上案例,换成.collect试试看:(注意!puts写在前面)
puts [100,200,300].collect {|n| n+50}
.collect会帮咱们把结果放入新的数组。结果印出(xujiaqing):
[150,250,350]
Array#map
一样的,.map方法也会帮咱们产生新的数组。
puts [100,200,300].map {|n| n+50}
结果印出:
[150,250,350]
那.collect与.map又有什么不一样?以及分别用在什么状况呢?这时候就要翻查Ruby手册里,关于.collect和.map的介绍了:
collect { |item| block }→new_ary Invokes the given block once for each element of self.Creates a new array containing the values returned by the block.
hmm…好像看不出有什么差别呢!
map { |obj| block }→array Returns a new array with the results of running block once for every element in enum.
近一步查询stackoverflow,果真有其余网友问过相似的问题。咱们能够把.map看成是.collect的别名(map is an alias for collect),实务上比较常使用.map喔!
更多Array#map用法
如今把个人银行账户数组存进account变数里,再用.inspect检查数组的值:
account = [100,200,300]
account.map {|n| n+50}
p account.inspect
结果印出
“[100,200,300]”
若是在.map后加上惊叹号.map!呢?
account.map!{|n| n+50}
p account.inspect
存进去本来的数组了。钱钱变多了!开心~~(加上!惊叹号的方法,一般表明当心!注意!的意思)
在这里的.map方法会让本来的物件数组被改变呢!
“[150,250,350]”
Hash
Hash哈希是一对key与value的集合。在刚刚的银行账户例子里,咱们能够把银行名称看成索引,存款数目看成值:
account = {“NAB”=> 100,“CAN”=> 200,“WEST”=> 300}
利用哈希来展示目前的信息(账户名称、存款金额),这样就可读性更加清楚了。
Hash#each
如今我想要计算三个账户加总共有多少钱,以.each的方式可写为:
mymoney = 0
account.each {|bankname,saving| mymoney += saving} #把索引和值列出
print“My Money: $”+ mymoney.to_s
或是
mymoney = 0 #设定初始值
account.each{|bank| mymoney += bank[1]} #依序加总bank集合里第二个元素bank[1]
print“My Money: $”+ mymoney.to_s
结果都会印出:
My Money: $ 600
Hash#map
在Hash里,把.each换成.map或是.collect:
mymoney = 0 #设定初始值
account.collect{|bank| mymoney += bank[1]} #依序加总bank集合里第二个元素bank[1]
print“My Money: $”+ mymoney.to_s
结果都是同样的:
My Money: $ 600
Hash#map结合Array#each与Array#map
如今要进阶到一个较为复杂的例子:hash里包含索引和值两部份,那咱们可不能够把数组看成一种值,放在里面呢?
固然能够!
假设个人NAB银行下有2个子账户,CAN银行下有3个子账户,分别放入这些资产:
hash = {“NAB”=> [“Cash”,“Gold”],“CAN”=> [“Bitcoin”,“Litecoin”,“Ethereum”] }
利用hash.map会产生一个新的数组:(进一步了解说明,看stackoverflow的说明)
p hash.map {|n| n}
结果显示:
[[“NAB”,[“Cash”,“Gold”]],[“CAN”,[“Bitcoin”,“Litecoin”,“Ethereum”]]] #我有好多账户!NAB下有2个,CAN下有3个
我想分别提取出银行:账户名称的这一对信息,而且用逗号.join(“,”)隔开。
为了程序可读性,hash的索引命名为bank(银行名),值为account_arry(放了不一样数目的子账户数组)。在走account_arry.each展开数组迭代器时,每在集合里走完一个元素,就印出#{bank}:#{sub_account}
p hash.map {
|bank,account_arry| account_arry.each{
|sub_account|“#{bank}:#{sub_account}”}
}.join(“,”)
结果仅印出:
“Cash,Gold,Bitcoin,Litecoin,Ethereum”
奇怪,这不是我要的结果呀!我很但愿账户前面能显示出银行名称呢!
这是由于刚刚说过,arry.each会回传数组自己,在这个例子里,分别回传的是[“Cash”,“Gold”]和[“Bitcoin”,“Litecoin”,“Ethereum”]
改为.map试试看:
p hash.map {
|bank,account_arry| account_arry.map{
|sub_account|“#{bank}:#{sub_account}”}
}.join(“,”)
结果显示为:
“NAB: Cash,NAB: Gold,CAN: Bitcoin,CAN: Litecoin,CAN: Ethereum”
这是由于account_arry.map自动帮咱们产生新的数组,放进bank与对应的sub_account并回传。
最后放个小小的比一比表格做为总结(expatvision):
each map / collect
Array方法Enumerable(列举)方法
回传Array自己产生新的Array并回传
祝福你们能顺利collect不一样的资产,不论是有形的财富、仍是无形的知识,最后均可以达成钱多多的心愿喔!:D