在这个例子中,
[1,2,3].each_with_index.map{|i,j| i * j} # => [0,6]
我的理解是,由于each_with_index枚举器被链接到map,map通过在块内传递索引来表现得像each_with_index,并返回一个新数组.
为了这,
[1,3].map.each_with_index{|i,6]
我不确定如何解释它.
在这个例子中,3,4].map.find {|i| i == 2} # => 2
我期望输出为[2],假设地图被链接到查找,并且map将返回一个新数组.
另外,我看到了这个:
[1,4].find.each_with_object([]){|i,j| j.push(i)} # => [1] [1,4].each_with_object([]).find{|i,j| i == 3} # => [3,[]]
你能让我知道如何解释和理解Ruby中的枚举链吗?
解决方法
您可能会发现打破这些表达式并使用IRB或PRY来查看Ruby正在做什么很有用.让我们从:
[1,3].each_with_index.map { |i,j| i*j }
让
enum1 = [1,3].each_with_index #=> #<Enumerator: [1,3]:each_with_index>
我们可以使用Enumerable#to_a(或Enumerable#entries)将enum1转换为数组,以查看它将传递给下一个枚举器(或者如果有一个块):
enum1.to_a #=> [[1,0],[2,1],[3,2]]
这并不奇怪.但是enum1没有块.相反,我们发送方法Enumerable#map:
enum2 = enum1.map #=> #<Enumerator: #<Enumerator: [1,3]:each_with_index>:map>
您可能会将此视为一种“复合”枚举器.这个枚举器确实有一个块,所以将它转换为一个数组将确认它会像enum1那样将相同的元素传递给块:
enum2.to_a #=> [[1,2]]
我们看到数组[1,0]是enum2传入块的第一个元素. “消歧”应用于此数组,以便为块变量分配值:
i => 1 j => 0
也就是说,Ruby正在设置:
i,j = [1,0]
enum2.each { |i,j| i*j } #=> [0,6]
接下来考虑:
[1,3].map.each_with_index { |i,j| i*j }
我们有:
enum3 = [1,3].map #=> #<Enumerator: [1,3]:map> enum3.to_a #=> [1,3] enum4 = enum3.each_with_index #=> #<Enumerator: #<Enumerator: [1,3]:map>:each_with_index> enum4.to_a #=> [[1,2]] enum4.each { |i,6]
由于enum2和enum4将相同的元素传递给块,我们看到这只是做同样事情的两种方式.
这是第三个等价链:
[1,3].map.with_index { |i,3] enum5 = enum3.with_index #=> #<Enumerator: #<Enumerator: [1,3]:map>:with_index> enum5.to_a #=> [[1,2]] enum5.each { |i,6]
为了更进一步,假设我们有:
[1,3].select.with_index.with_object({}) { |(i,j),h| ... }
我们有:
enum6 = [1,3].select #=> #<Enumerator: [1,3]:select> enum6.to_a #=> [1,3] enum7 = enum6.with_index #=> #<Enumerator: #<Enumerator: [1,3]:select>:with_index> enum7.to_a #=> [[1,2]] enum8 = enum7.with_object({}) #=> #<Enumerator: #<Enumerator: #<Enumerator: [1,3]: # select>:with_index>:with_object({})> enum8.to_a #=> [[[1,{}],[[2,[[3,2],{}]]
第一个元素enum8进入块是数组:
(i,h = [[1,{}]
然后应用消歧来为块变量赋值:
i => 1 j => 0 h => {}
请注意,enum8显示了在enum8.to_a的三个元素中的每个元素中传递的空哈希,但当然这仅仅是因为Ruby在传入第一个元素后不知道哈希的样子.