Ruby 枚举器链接 [英] Ruby enumerator chaining
问题描述
在这个例子中,
[1, 2, 3].each_with_index.map{|i, j| i * j}
# => [0, 2, 6]
我的理解是,由于 each_with_index
枚举器链接到 map
,map
的行为类似于 each_with_index
通过传递块内的索引,并返回一个新数组.
my understanding is that, since each_with_index
enumerator is chained to map
, map
behaves like each_with_index
by passing an index inside the block, and returns a new array.
为此,
[1, 2, 3].map.each_with_index{|i, j| i * j}
# => [0, 2, 6]
我不知道如何解释它.
在这个例子中,
[1, 2, 3, 4].map.find {|i| i == 2}
# => 2
我期望输出为 [2]
,假设 map
链接到 find
和 map
将返回一个新数组.
I was expecting the the output to be [2]
, assuming that map
is chained to find
, and map
would return a new array.
另外,我看到这个:
[1, 2, 3, 4].find.each_with_object([]){|i, j| j.push(i)}
# => [1]
[1, 2, 3, 4].each_with_object([]).find{|i, j| i == 3}
# => [3, []]
你能告诉我如何解释和理解 Ruby 中的枚举器链吗?
Can you let me know how to interpret and understand enumerator chains in Ruby?
推荐答案
您可能会发现分解这些表达式并使用 IRB 或 PRY 来查看 Ruby 正在做什么很有用.让我们开始:
You might find it useful to break these expressions down and use IRB or PRY to see what Ruby is doing. Let's start with:
[1,2,3].each_with_index.map { |i,j| i*j }
让
enum1 = [1,2,3].each_with_index
#=> #<Enumerator: [1, 2, 3]:each_with_index>
我们可以使用 Enumerable#to_a(或Enumerable#entries)转换enum1
到一个数组,以查看它将传递给下一个枚举器(或传递给一个块,如果有的话):
We can use Enumerable#to_a (or Enumerable#entries) to convert enum1
to an array to see what it will be passing to the next enumerator (or to a block if it had one):
enum1.to_a
#=> [[1, 0], [2, 1], [3, 2]]
毫不奇怪.但是 enum1
没有块.相反,我们向它发送方法 Enumerable#map:
No surprise there. But enum1
does not have a block. Instead we are sending it the method Enumerable#map:
enum2 = enum1.map
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:each_with_index>:map>
您可能会认为这是一种复合"枚举器.此枚举器确实有一个块,因此将其转换为数组将确认它将向块中传递与 enum1
相同的元素:
You might think of this as a sort of "compound" enumerator. This enumerator does have a block, so converting it to an array will confirm that it will pass the same elements into the block as enum1
would have:
enum2.to_a
#=> [[1, 0], [2, 1], [3, 2]]
我们看到数组 [1,0]
是 enum2
传入块的第一个元素.消歧"应用于此数组以将值分配给块变量:
We see that the array [1,0]
is the first element enum2
passes into the block. "Disambiguation" is applied to this array to assign the block variables the values:
i => 1
j => 0
也就是说,Ruby 正在设置:
That is, Ruby is setting:
i,j = [1,0]
我们现在可以通过将方法 each
与块一起发送来调用 enum2
:
We now can invoke enum2
by sending it the method each
with the block:
enum2.each { |i,j| i*j }
#=> [0, 2, 6]
接下来考虑:
[1,2,3].map.each_with_index { |i,j| i*j }
我们有:
enum3 = [1,2,3].map
#=> #<Enumerator: [1, 2, 3]:map>
enum3.to_a
#=> [1, 2, 3]
enum4 = enum3.each_with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:map>:each_with_index>
enum4.to_a
#=> [[1, 0], [2, 1], [3, 2]]
enum4.each { |i,j| i*j }
#=> [0, 2, 6]
由于 enum2
和 enum4
将相同的元素传递到块中,我们看到这只是做同样事情的两种方式.
Since enum2
and enum4
pass the same elements into the block, we see this is just two ways of doing the same thing.
这是第三个等效链:
[1,2,3].map.with_index { |i,j| i*j }
我们有:
enum3 = [1,2,3].map
#=> #<Enumerator: [1, 2, 3]:map>
enum3.to_a
#=> [1, 2, 3]
enum5 = enum3.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:map>:with_index>
enum5.to_a
#=> [[1, 0], [2, 1], [3, 2]]
enum5.each { |i,j| i*j }
#=> [0, 2, 6]
为了更进一步,假设我们有:
To take this one step further, suppose we had:
[1,2,3].select.with_index.with_object({}) { |(i,j),h| ... }
我们有:
enum6 = [1,2,3].select
#=> #<Enumerator: [1, 2, 3]:select>
enum6.to_a
#=> [1, 2, 3]
enum7 = enum6.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:select>:with_index>
enum7.to_a
#=> [[1, 0], [2, 1], [3, 2]]
enum8 = enum7.with_object({})
#=> #<Enumerator: #<Enumerator: #<Enumerator: [1, 2, 3]:
# select>:with_index>:with_object({})>
enum8.to_a
#=> [[[1, 0], {}], [[2, 1], {}], [[3, 2], {}]]
enum8
传入块的第一个元素是数组:
The first element enum8
passes into the block is the array:
(i,j),h = [[1, 0], {}]
然后应用消歧来为块变量赋值:
Disambiguation is then applied to assign values to the block variables:
i => 1
j => 0
h => {}
请注意,enum8
显示了在 enum8.to_a
的三个元素中的每一个中传递的空散列,但这当然只是因为 Ruby 不知道hash 会在第一个元素传入后看起来像.
Note that enum8
shows an empty hash being passed in each of the three elements of enum8.to_a
, but of course that's only because Ruby doesn't know what the hash will look like after the first element is passed in.
这篇关于Ruby 枚举器链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!