在Scala中是否可以“流”最大化for-comprehension的输出?

shstlldc  于 2023-08-05  发布在  Scala
关注(0)|答案(1)|浏览(105)

我正在Scala中处理一个问题,其中我有两个输入Seq[Int]AB,以及一个值函数f,目标是找到AB中任何一对元素(a, b)``f
我们可以用for-comprehension简单地做到这一点:

val A = Seq(1, 2, 3, 4, 5)
val B = Seq(6, 7, 8, 9, 10)
def f(a: Int, b: Int): Int = a * b // f can be more complex than just a multiplication. This is just an example. 

val results = for {
  a <- A
  b <- B
} yield f(a, b)

results.max

字符串
我遇到的问题是AB可能非常大,计算(a, b)的每个组合都会导致内存错误。我实际上并不关心整个(a, b)列表,甚至也不关心整个results列表。我只关心最大值。
是否可以将for-comprehension生成的值列表流到f中,然后再流到max函数中,这样我就不必在内存中保存整个列表了?
注记

  • 我正在处理的问题是Leetcode #11 -最多水的容器。我知道线性时间解决方案,但我真正好奇的是,我们是否可以在Scala中将一个逻辑值序列流到聚合器函数中。
  • 在我的研究中,我发现了scala Streams,它看起来像当前LazyList类的前一个实现,但它们看起来不会给予我想要的行为。我不认为“流”是描述我在scala中想要的行为的合适的词,但我不确定下一步该搜索什么。
6vl6ewon

6vl6ewon1#

我看了看评论,采取了实验性的方法。我启动了一个Scala shell并运行了以下两段代码。
使用LazyList

val a = LazyList.continually(0).take(Int.MaxValue)
val b = LazyList.continually(0).take(Int.MaxValue)
val results = for (a <- a; b <- b) yield (a, b)
results.max

字符串
LazyList不只是懒惰地计算集合,而且还试图保留它,这意味着集合将“泄漏”,即使这不是您正在寻找的行为。在我的测试运行中发生的情况是,进程从未用完内存(尽管我相信它最终会用完),但总是有一点内存需要回收,因此发生了如此多的垃圾收集,以至于进程实际上停止了有意义的进程。请参阅以下VisualVM内存监控图表:


的数据
使用Iterator

val a = Iterator.continually(0).take(Int.MaxValue)
val b = Iterator.continually(0).take(Int.MaxValue)
val results = for (a <- a; b <- b) yield (a, b)
results.max


Iterator被 * 消耗 *(即有一个副作用),但不尝试记忆集合,这意味着可以收集已评估的项。这是在我的笔记本电脑上运行了几分钟。在VisualVM图表中可以看到内存是如何逐步消耗的,然后在“垃圾”开始堆积时回收:


相关问题