Ruby Lazy Enumerable flat_map 不是很懒

Posted

技术标签:

【中文标题】Ruby Lazy Enumerable flat_map 不是很懒【英文标题】:Ruby Lazy Enumerable flat_map is not very lazy 【发布时间】:2015-02-07 16:06:55 【问题描述】:

编辑:由于我用错误的示例写了问题并且没有描述我的问题,我会再做一次!

在我看来,#flat_map 尽管是 Enumerator::Lazy 类的一部分,但它本身并不是非常可枚举的。

这个例子可以正常工作:

(1..Float::INFINITY).flat_map  |s| [s,s] .take(4).to_a

惰性实现也可以:

(1..Float::INFINITY).flat_map  |s| [s,s] .take(4).to_a

这只会考虑块内生成的数组是有限的。但它们也将在 take(4) 调用发生之前进行全面评估。这不是很懒惰。

因此,这将失败:

(1..Float::INFINITY).lazy.flat_map  |i| (i..Float::INFINITY).map(&:to_i) .take(4).force

因为“数组的无穷大范围”将在惰性调用发生之前被完全评估。不过,我希望它“默认是懒惰的”。我的意思是,我确实理解难题所在,但我希望它会以这种方式发生:flat_map 评估每个实例惰性,知道结果将是一个数组(或至少是可枚举的),并将应用惰性机制在上面。因此, (i..Float::INFINITY).map(&:to_i) 将被惰性化(这似乎不太兼容,因为 map(&:to_i) 调用将“强制”计算它)。

【问题讨论】:

这可能是实现中的错误。 @tadman:OP 是flat_mapping Range,而不是Enumerator::Lazy。这里根本没有懒惰,你也不希望有。 耶稣,现在才注意到缺少的#lazy 调用...我将不得不回到我失败的示例,看看我最初的问题是什么。 很抱歉,我在包装惰性集合时遇到了问题。我会尝试重写 前两行代码不完全一样吗?为什么你说一个是懒惰的而另一个不是 【参考方案1】:

您实际上并没有使用惰性枚举器。要将普通枚举器转换为惰性枚举器,请使用Enumerable#lazy 方法。为了得到结果,我建议使用 Enumerable::Lazy#force 而不是 to_a 方法,因为我认为它更清楚地表明了意图。

(1..Float::INFINITY).lazy.flat_map  |s| [s,s] .take(4).force
#=> [1, 1, 2, 2]

【讨论】:

以上是关于Ruby Lazy Enumerable flat_map 不是很懒的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Enumerable 在 Ruby 中没有长度属性?

ruby 更好的Ruby Enumerable模块

将 Enumerable 转换为 Hash 的 Ruby 库函数

ruby is_enumerable.rb

ruby 使用Enumerable逐行迭代文件

ruby 使用Enumerable逐行迭代文件