Dea*_*ffe 6 ruby enumerable enumerator
从我发现的一个例子中,这段代码计算了数组中与其索引相等的元素数.但是怎么样?
[4, 1, 2, 0].to_enum(:count).each_with_index{|elem, index| elem == index}
Run Code Online (Sandbox Code Playgroud)
我不可能只通过链接来完成它,链中的评估顺序令人困惑.
我理解的是Enumerable#count,如果给出一个块,我们将使用其重载计算产生真值的元素数.我看到它each_with_index有关于该项是否等于它的索引的逻辑.
我不明白的是如何each_with_index成为块参数count,或者为什么each_with_index工作就像是直接调用它一样[4,1,2,0].如果map_with_index存在,我本可以做到:
[4,1,2,0].map_with_index{ |e,i| e==i ? e : nil}.compact
Run Code Online (Sandbox Code Playgroud)
但请帮助我理解这种基于可枚举的风格 - 它很优雅!
小智 5
让我们从一个更简单的例子开始:
[4, 1, 2, 0].count{|elem| elem == 4}
=> 1
Run Code Online (Sandbox Code Playgroud)
所以这里count方法返回1,因为该块对于数组的一个元素(第一个元素)返回true.
现在让我们来看看你的代码.首先,Ruby在调用to_enum时创建一个枚举器对象:
[4, 1, 2, 0].to_enum(:count)
=> #<Enumerator: [4, 1, 2, 0]:count>
Run Code Online (Sandbox Code Playgroud)
这里枚举器正在等待使用[4,1,2,0]数组和count方法执行迭代.枚举器就像一个挂起的迭代,等待稍后发生.
接下来,在枚举器上调用each_with_index方法,并提供一个块:
...each_with_index{|elem, index| elem == index}
Run Code Online (Sandbox Code Playgroud)
这将调用您在上面创建的枚举器对象上的Enumerator#each_with_index方法.Enumerator#each_with_index所做的是使用给定的块启动挂起的迭代.但它也将索引值与迭代中的值一起传递给块.由于挂起的迭代设置为使用count方法,因此枚举器将调用Array#count.这将每个元素从数组传递回枚举器,枚举器将它们与索引一起传递到块中.最后,Array#count计算真实值,就像上面的简单示例一样.
对我来说,理解这一点的关键是你正在使用Enumerator#each_with_index方法.
只需点击一下即可找到答案:Enumerator的文档:
大多数 [
Enumerator] 方法 [但可能还有Kernel#to_enum和Kernel#enum_for] 有两种形式:一种是块形式,其中针对枚举中的每个项目计算内容;另一种是非块形式,它返回一个新的Enumerator迭代包装。
这里适用的是第二个:
enum = [4, 1, 2, 0].to_enum(:count) # => #<Enumerator: [4, 1, 2, 0]:count>
enum.class # => Enumerator
enum_ewi = enum.each_with_index
# => #<Enumerator: #<Enumerator: [4, 1, 2, 0]:count>:each_with_index>
enum_ewi.class # => Enumerator
enum_ewi.each {|elem, index| elem == index} # => 2
Run Code Online (Sandbox Code Playgroud)
特别注意第三行的 irb 返回。它继续说道:“这允许您将枚举器链接在一起。” 并给出map.with_index一个例子。
为什么停在这里?
enum_ewi == enum_ewi.each.each.each # => true
yet_another = enum_ewi.each_with_index
# => #<Enumerator: #<Enumerator: #<Enumerator: [4, 1, 2, 0]:count>:each_with_index>:each_with_index>
yet_another.each_with_index {|e,i| puts "e = #{e}, i = #{i}"}
e = [4, 0], i = 0
e = [1, 1], i = 1
e = [2, 2], i = 2
e = [0, 3], i = 3
yet_another.each_with_index {|e,i| e.first.first == i} # => 2
Run Code Online (Sandbox Code Playgroud)
(编辑 1:将文档中的示例替换为与问题相关的示例。编辑 2:添加“为什么停在这里?)
| 归档时间: |
|
| 查看次数: |
993 次 |
| 最近记录: |