gpt4 book ai didi

ruby - 在 Ruby 中概念化枚举器和惰性枚举器

转载 作者:数据小太阳 更新时间:2023-10-29 08:22:25 27 4
gpt4 key购买 nike

我需要一些帮助来概念化 Ruby 中的 Lazy Enumerator 对象。

我认为 Enumerator 对象是集合的“有状态”版本。该对象了解哪些元素是集合的一部分,以及应该产生的“下一个”元素是什么。它是一个知道它的元素是 1、2 和 3 的对象,它已经产生 1 和 2,因此如果被要求它会产生 3。

假设 Enumerator 的概念化是正确的,我很难理解 Lazy Enumerator 的工作原理。惰性枚举器是在“常规”枚举器的基础上构建的,但不应该事先计算其集合。例如,来自 The Ruby Way:

enum = (1..Float::INFINITY).each
lazy = enum.lazy
odds = lazy.select(&:odd)

如果惰性枚举器是从惰性枚举器构建的,那么惰性枚举器是如何惰性的,因为我正在做枚举器部分,这可能不是惰性的,首先?

最佳答案

Enumerator#lazy 允许您有效地创建一系列可枚举操作,这些操作应用于从可枚举迭代而来的每个值。相比之下,普通枚举器对可枚举中的所有值执行每个操作,然后将结果沿着链向下传递到链中的下一个操作。您可以将惰性枚举器视为“深度优先”操作,将普通枚举器视为“广度优先”操作。

普通枚举器返回枚举的结果:

> (1..10).select(&:odd?)
=> [1, 3, 5, 7, 9]

如果您要链接这些操作,您可以对有限的值列表执行一些操作列表:

> (1..10).select(&:odd?)
=> [1, 3, 5, 7, 9]

> (1..10).select(&:odd?).map {|v| v * 2 }
=> [2, 6, 10, 14, 18]

在将值列表传递到链下以进行下一个操作之前,链中的每个操作都应用于可枚举中的所有值。

相比之下,Enumerable#lazy 从每个操作中返回惰性枚举器(“与值相关的事情”):

> (1..10).lazy.select(&:odd?)
=> #<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:select>
> (1..10).lazy.select(&:odd?).map {|v| v * 2 }
=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:select>:map>

如您所见,它不会在链中的每次调用中处理整个值列表。相反,当您从可枚举中合并一个值时(例如,使用#next),然后从底层可枚举中获取下一个值,然后通过每个可枚举操作传递,最后返回:

> (1..10).lazy.select(&:odd?).map {|v| v * 2 }.next
=> 2

如果您要在无限列表上尝试这些相同的操作,那么非惰性枚举器将永远停止,因为它会尝试对无限枚举进行广度优先传递,这显然永远不会终止!

关于ruby - 在 Ruby 中概念化枚举器和惰性枚举器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30416665/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com