2015-05-29 26 views
4

一个Enumerator对象可以通过调用某些方法而没有经过块,例如Array#reject创建:什么时候是一个枚举器有用?

(1..3).reject.to_a 
# => [1, 2, 3] 

这只是为了便于链接一些红宝石的规则或者是有一些其他的方式来传递行为的枚举?

+1

“有没有其他方法可将行为传递给枚举器?” - 不确定你的意思。 –

+2

我并不不同意你决定给@Sergio颁奖,但下次考虑等一会儿(至少几个小时),然后再作出决定。快速选择(在发布问题后大约25分钟)可以阻止其他答案,并且不会被那些仍在解答他们答案的人所赞赏。即使随后的答案不是“更好”,它们可能包含有用的观察结果,您可能可以在其他情况下应用。没有急于。 –

回答

4

这只是为了便于链接

是的,这正是原因红宝石的一些规则。调查员容易链接。考虑下面这个例子:

ary = ['Alice', 'Bob', 'Eve'] 

records = ary.map.with_index do |item, idx| 
    { 
    id: idx, 
    name: item, 
    } 
end 

records # => [{:id=>0, :name=>"Alice"}, {:id=>1, :name=>"Bob"}, {:id=>2, :name=>"Eve"}] 

map产生每个元素with_index,其中掴在它上面和产量,以你的模块项目索引。块返回值为with_index,返回map做它的事,映射和)返回给调用者。

1

这只是为了便于链接

这不是红宝石的规则有些红宝石的规则。只是在没有块的情况下调用reject方法(例如)返回Enumerator。它可以做其他的事情。

或者是否有其他方式将行为传递给Enumerator

是的,Enumerator封装了您创建Enumerator的方法的行为。例如,从reject创建Enumerator会创建一个会拒绝其某些元素的对象。 EnumeratorEnumerable中混合,因此可以对此Enumerator做任何事情,您可以使用任何其他Enumerable。例如:

enum = (1..3).reject 

enum.with_index {|el, i| i.even? } 
# => [2] 
+0

能够将拒绝行为传递给枚举的一个很好的例子。 – 7stud

1

正如@Sergio所说,它主要是用于链接,但它不止于此。如果你有一个枚举器,e,你可以使用Enumerator#nextEnumerator#peek来提取元素。这里有两个例子说明如何使用统计员的优势。

问题:给定的阵列a,构建另一个数组索引i,其值是如果a[i]i奇数和2*a[i]如果i是偶数。假设a = [1,2,3,4]

人们会通常看到:

a.map.with_index { |n,i| n.odd? ? n : 2*n } #=> [1,4,3,8] 

但是这也可以写成:

e = [1,2].cycle   #=> #<Enumerator: [1, 2]:cycle> 
a.map { |n| e.next * n } #=> [1, 4, 3, 8] 

问题:给定的阵列a,即相等成阵列块连续值。让我通过展示它通常如何完成来更准确地阐述这一说法。假设a = [1,1,2,3,3,3,4]

a.chunk(&:itself).map(&:last) #=> [[1, 1], [2], [3, 3, 3], [4]] 

在Ruby V2.2(其中#itself首次亮相),你可以使用Enumerable#slice_when

a.slice_when { |f,l| f != l }.to_a 
    #=> [[1, 1], [2], [3, 3, 3], [4]] 

,但你也可以使用一个枚举:

e = a.to_enum 
    #=> #<Enumerator: [1, 1, 2, 3, 3, 3, 4]:each> 
b = [[]] 
loop do 
    n = e.next 
    b[-1] << n 
    nxt = e.peek 
    b << [] if nxt != n 
end 
b 
    #=> [[1, 1], [2], [3, 3, 3], [4]] 

注意,当ne的最后一个值,e.peek会引起StopInteration异常。通过跳出循环,该例外由Kernel#loop处理。

我并不是建议这个最后的方法应该优先于我提到​​的其他两个选项,但还有其他情况下可以有效地使用这种方法。

还有一件事:如果您有链接方法的表达式,则可以通过将枚举器转换为数组来检查其元素传递到块的枚举器的内容。从中你可以看到需要哪些块变量。假设你想写:

[1,2,3,4].each_with_index.with_object({}) {....} 

并在块中做些事情,但不确定如何表示块变量。你可以这样做:

e = [1,2,3,4].each_with_index.with_object({}) 
    #=> #<Enumerator: #<Enumerator: [1, 2, 3, 4]:each_with_index> 
     :with_object({})> 
e.to_a 
    #=> [[[1, 0], {}], [[2, 1], {}], [[3, 2], {}], [[4, 3], {}]] 

这表明,(说)传递到块的e第一个元素是:

[[1, 0], {}] 

告诉使用该块变量应该是:

(n,i), h = [[1, 0], {}] 
n #=> 1 
i #=> 0 
h #=> {} 

意思是表达方式应该写成:

[1,2,3,4].each_with_index.with_object({}) { |(n,i),h|....} 
相关问题