3

我在理解 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方法吗?如果有人可以解释,那就太好了。

4

2 回答 2

3

来自编程 Ruby:

计数 枚举.count {| 对象 | 块 } → int

返回枚举中等于 obj 或块返回真值的对象的计数。

因此,枚举器访问每个元素并在块返回 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

ab通过“喷溅”的块参数来获取它们的值:

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 }

这对我来说似乎比原来的例子更清楚。

于 2012-11-12T20:14:04.053 回答
0

array.count通常可以采用一个块,但它本身返回一个固定编号,因此它不能.with_index像其他一些迭代器(tryarray.map.with_index {|x,i ... }等)那样链接到。

.enum_for(:count)将其转换为枚举器,从而允许进行链接。它遍历数组的成员一次,并记录其中有多少等于它们的索引。所以 count 实际上只被调用一次,但只有在将数组转换为更灵活的东西之后。

于 2012-11-12T19:58:03.363 回答