我不是说数组-> |值,索引|和哈希-> |键,值|不是疯狂的(见Horace Loeb的评论),但我是说有一种理智的方式来期望这种安排。
当我处理数组时,我关注的是数组中的元素(而不是索引,因为索引是临时的)。方法是每个带索引,即每个+索引,或|每个,索引|,或|值,索引|。这也与索引被视为可选参数相一致,例如|值|相当于|值,index=nil|与|值一致,index|。
当我处理散列时,我通常更关注键而不是值,并且我通常按此顺序处理键和值,key => value或hash[key] = value。
如果需要鸭子类型,那么可以显式使用Brent Longborough所示的已定义方法,也可以使用maxhawkins所示的隐式方法。
Ruby就是让语言适应程序员,而不是让程序员适应语言。这就是为什么有这么多方法。思考一件事有很多种方式。在Ruby中,你选择最接近的代码,其余的代码通常会非常简洁。
至于最初的问题,“在Ruby中迭代数组的“正确”方法是什么?”,我认为核心方法(即没有强大的语法糖或面向对象的能力)是:
for index in 0 ... array.size
puts "array[#{index}] = #{array[index].inspect}"
end
但是Ruby是关于强大的语法糖和面向对象的能力的,但无论如何,这里有等效的哈希值,键可以是有序的,也可以不是:
for key in hash.keys.sort
puts "hash[#{key.inspect}] = #{hash[key].inspect}"
end
所以,我的回答是,“在Ruby中迭代数组的“正确”方式取决于你(即程序员或编程团队)和项目。”更好的Ruby程序员会做出更好的选择(选择哪种语法能力和/或哪种面向对象的方法)。优秀的Ruby程序员会继续寻找更多的方法。
现在,我想问另一个问题,“在Ruby中反向迭代Range的“正确”方法是什么?”!(这个问题是我如何来到这个页面的。)
(对于远期)这样做很好:
(1..10).each{|i| puts "i=#{i}" }
but I don't like to do (for backward):
(1..10).to_a.reverse.each{|i| puts "i=#{i}" }
其实,我并不介意这么做,但当我在逆向教学时,我想向我的学生展示一个漂亮的对称(即差别最小,例如只添加反向,或步长-1,但不修改其他任何东西)。
你可以这样(为了对称):
(a=*1..10).each{|i| puts "i=#{i}" }
and
(a=*1..10).reverse.each{|i| puts "i=#{i}" }
我不太喜欢,但你做不到
(*1..10).each{|i| puts "i=#{i}" }
(*1..10).reverse.each{|i| puts "i=#{i}" }
#
(1..10).step(1){|i| puts "i=#{i}" }
(1..10).step(-1){|i| puts "i=#{i}" }
#
(1..10).each{|i| puts "i=#{i}" }
(10..1).each{|i| puts "i=#{i}" } # I don't want this though. It's dangerous
你最终可以做到
class Range
def each_reverse(&block)
self.to_a.reverse.each(&block)
end
end
但我想教纯Ruby,而不是面向对象的方法(目前)。我想向后迭代:
不需要创建数组(考虑0..1000000000)
适用于任何范围(例如字符串,而不仅仅是整数)
无需使用任何额外的面向对象功能(即无需修改类)
我相信如果不定义一个pred方法,这是不可能的,这意味着修改Range类来使用它。如果您能做到这一点,请让我知道,否则确认不可能将不胜感激,尽管这将是令人失望的。也许Ruby 1.9解决了这个问题。
(感谢您花时间阅读本文。)