【问题标题】:How does Ruby enumerator terminate iteration?Ruby 枚举器如何终止迭代?
【发布时间】:2020-09-04 09:51:32
【问题描述】:

朋友,我需要帮助解释一下:在下面的 Ruby 代码中,循环做什么条件白蚁?它应该是一个无限循环,但是,它是如何终止的呢?

# Ruby code
fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end

p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

我们将非常感谢您的贡献。

【问题讨论】:

  • 顺便说一句,在 Ruby v2.7 中,Ruby 僧侣为我们提供了 Enumerator::produce 方法,它简化了一些枚举器的创建,包括生成斐波那契数的枚举器:enum = Enumerator.produce([0, 1]) {|n1, n2| [n2, n2+n1]}。例如,前 8 个斐波那契数由 arr = enum.take(8) #=&gt; [[0, 1], [1, 1], [1, 2], [2, 3], [3, 5], [5, 8], [8, 13], [13, 21]] 给出,然后是 arr.map(&amp;:first) #=&gt; [0, 1, 1, 2, 3, 5, 8, 13]

标签: ruby enumerable enumerator take


【解决方案1】:

(来源:https://rossta.net/blog/infinite-sequences-in-ruby.html

您实现函数fib 的方式使其变得“懒惰”。这意味着,Ruby 不会尝试计算 fib 中的值,除非它绝对必须这样做。

最后一行的take 方法是这里的关键。

p fib.take(10) 

基本上,Ruby 说“我将评估 fib 的前 10 个值并假装其余的值不存在,因为我还没有必须使用它们。”

换句话说,虽然fib 函数确实可能是无限的,但您只要求了前 10 个值,因此您只得到了前 10 个值。

如果你尝试过这样的事情:

p fib.to_a

您的程序会卡住。为什么?因为to_a (to array) 方法想要尝试获取 all fib 的值,而不仅仅是其中的几个。显然,您无法获得所有无限列表的值。

更多信息:

https://medium.com/background-thread/what-is-lazy-evaluation-programming-word-of-the-day-8a6f4410053f

https://github.com/juinc/tilap/issues/9

--- 编辑:---

技术更正:正如 Cary Swoveland 指出的那样,说fib 是一种按需生成值的算法/机器,在技术上更正确。

【讨论】:

    【解决方案2】:

    枚举器就像Pez® dispenser,每次按下分配器的顶部时都会弹出一个薄荷糖。枚举器版本的分配器不会供应糖果,但会根据需要一次制造一个糖果,可能能够生产无限数量的糖果。

    一种类型的枚举器与底层对象集合相关联。这里有两个绑定到一个数组。

    enum = [1,2,3].each #=> #<Enumerator: [1, 2, 3]:each> 
    
    enum.next #=> 1 
    enum.next #=> 2 
    enum.next #=> 3 
    enum.next #=> StopIteration (iteration reached an end) 
    

    enum = [1,2,3].cycle #=> #<Enumerator: [1, 2, 3]:cycle> 
    
    enum.next #=> 1 
    enum.next #=> 2 
    enum.next #=> 3 
    enum.next #=> 1 
    enum.next #=> 2 
    ... ad infinitum
    
    enum.first(8)
      #=> [1, 2, 3, 1, 2, 3, 1, 2] 
    

    在第一个示例中,在引发StopIteration 异常之前,枚举器仅生成有限数量的对象。在第二个示例中,可以生成任意数量的对象,但只能按需生成。例如,first 指示 enum 8 次生成并传递给自己一个对象。 enum 不是 懒惰的;它急于遵守,但在得到指示之前不会制造和分发物品。

    另一种类型的枚举器根据它与生俱来的一组规则生成对象,这些规则与底层对象无关。这些枚举器通常能够生成无限数量的对象。生成斐波那契数的枚举器就是这种类型的枚举器的一个示例。它不是一个不终止的循环;它是一种能够按需生产任意数量的物体的机器,但一次只能生产一个。

    【讨论】:

      猜你喜欢
      • 2011-02-06
      • 2012-06-08
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 2016-12-16
      • 1970-01-01
      • 1970-01-01
      • 2017-12-01
      相关资源
      最近更新 更多