我在理解Ruby中的枚举器时遇到了麻烦。
请纠正我如果我错了,o.enum_for(:arg)
方法应该将对象转换为枚举器,对象o
上的每次迭代都应该调用arg
方法?
令我困惑的是这行代码如何工作
[4, 1, 2, 0].enum_for(:count).each_with_index do |elem, index|
elem == index
end
它应该计算有多少元素等于它们在数组中的位置,并且它可以工作。但是,我不明白实际发生了什么。 each_with_index
每次迭代都调用count方法吗?如果有人能够解释,那就太好了。
答案 0 :(得分:3)
来自编程Ruby:
计数 enum.count {| obj | block}→int
返回枚举中等于obj或者对象的对象的数量 block返回一个真值。
因此,如果块返回true,则枚举器访问每个元素并将1加到计数中,在这种情况下,这意味着元素是否等于数组索引。
我没有看到这种模式使用太多(如果有的话) - 我更倾向于:
[4, 1, 2, 0].each_with_index.select { |elem, index| elem == index }.count
修改强> 的
让我们看一下评论中的示例:
[4, 1, 2, 0].enum_for(:each_slice, 2).map do |a, b|
a + b
end
each_slice(2)
一次获取数组2个元素,并为每个切片返回一个数组:
[4, 1, 2, 0].each_slice(2).map # => [[4,1], [2,0]]
在结果上调用map
让我们对每个子数组进行操作,并将其传递给一个块:
[4, 1, 2, 0].enum_for(:each_slice, 2).map do |a,b|
puts "#{a.inspect} #{b.inspect}"
end
结果
4 1
2 0
a
和b
凭借块参数“splatted”获取其值:
a, b = *[4, 1]
a # => 4
b # => 1
您也可以将数组切片作为参数:
[4, 1, 2, 0].enum_for(:each_slice, 2).map {|a| puts "#{a.inspect}"}
[4, 1]
[2, 0]
这可以让你这样做:
[4, 1, 2, 0].enum_for(:each_slice, 2).map {|a| a.inject(:+) } #=> [5,2]
或者如果您有ActiveSupport(即Rails应用程序),
[4, 1, 2, 0].enum_for(:each_slice, 2).map {|a| a.sum }
对我而言,这比原始示例更清晰。
答案 1 :(得分:0)
array.count
通常可以占用一个块,但是它自己会返回一个fixnum,所以它不能像其他迭代器一样链接到.with_index
(尝试array.map.with_index {|x,i ... }
等等。)
.enum_for(:count)
将其转换为枚举器,允许进行链接。它在数组成员上迭代一次,并保持其中有多少等于其索引的计数。所以count实际上只被调用一次,但只有在将数组转换为更灵活的东西之后才会被调用。