我并不是说
Array
->
|value,index|
和
Hash
->
|key,value|
这样的写法不合理(可以看 Horace Loeb 的评论),但我认为有一种更加合理的写法。
当我处理数组时,我关注的是数组中的元素(而非索引,因为索引是暂时的)。这个方法是 each with index,即 each+index,或 |each,index|,或
|value,index|
。这也与将索引视为可选参数相符,例如 |value| 相当于 |value,index=nil|,这与 |value,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中倒序遍历范围的‘正确’方法是什么?”(这个问题是我来到这个页面的原因。)
(对于正向)做起来很不错:
(1..10).each{|i| puts "i=#{i}" }
但我不喜欢做(向后):
(注意:保留了HTML标签)
(1..10).to_a.reverse.each{|i| puts "i=#{i}" }
嗯,我并不介意这样做,但当我倒着教学时,我想向我的学生展示一个漂亮的对称性(即最小差异,例如只添加一个反转或步骤-1,但不修改任何其他内容)。
您可以执行以下操作(以实现对称性):
(a=*1..10).each{|i| puts "i=#{i}" }
并且
(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}" }
您最终可以做的是:
class Range
def each_reverse(&block)
self.to_a.reverse.each(&block)
end
end
但我想教授的是纯Ruby而不是面向对象的方法(暂时不适用)。 我想要反向迭代:
- 不创建数组(考虑0..1000000000)
- 适用于任何范围(例如字符串,而不仅仅是整数)
- 不使用任何额外的面向对象编程技巧(即不修改类)
我认为这是不可能的,除非定义一个
pred
方法,这意味着修改Range类来使用它。如果您能够做到这一点,请让我知道,否则请确认无法实现,尽管这会令人失望。也许Ruby 1.9可以解决这个问题。
(感谢您阅读此内容所花费的时间。)
array#each_with_index
使用|value, key|
是因为方法名暗示了顺序,而hash#each
使用的顺序模仿了hash[key] = value
语法? - Benjineer