scala - Scala 中无限流的嵌套迭代

标签 scala stream for-comprehension

我有时发现自己想要在 Scala 中的无限流上执行嵌套迭代 for 推导式,但指定循环终止条件可能有点棘手。有没有更好的方法来做这种事情?

我想到的用例是,我不一定预先知道我正在迭代的每个无限流中需要多少个元素(但显然我知道它不会是无限个) )。假设每个流的终止条件可能以某种复杂的方式取决于 for 表达式中其他元素的值。

最初的想法是尝试将流终止条件编写为 for 表达式中的 if 过滤子句,但是当循环嵌套的无限流时,这会遇到麻烦,因为无法使第一个无限流上的迭代短路,这最终会导致 OutOfMemoryError。考虑到 for 表达式如何映射到 ma​​pflatMapwithFilter 方法调用,我明白为什么会出现这种情况 -我的问题是是否有更好的习惯用法来完成这种事情(也许根本不涉及 for 理解)。

为了给出一个有点人为的示例来说明刚刚描述的问题,请考虑以下(非常简单的)代码来生成数字 1 和 2 的所有配对:

val pairs = for {
  i <- Stream.from(1) 
  if i < 3 
  j <- Stream.from(1) 
  if j < 3
} 
yield (i, j)

pairs.take(2).toList 
// result: List[(Int, Int)] = List((1,1), (1,2)) 

pairs.take(4).toList
// 'hoped for' result: List[(Int, Int)] = List((1,1), (1,2), (2,1), (2,2))
// actual result:
//  java.lang.OutOfMemoryError: Java heap space
//      at scala.collection.immutable.Stream$.from(Stream.scala:1105)

显然,在这个简单的示例中,通过将 if 过滤器移动到原始流上的 takeWhile 方法调用中,可以轻松避免该问题,如下所示:

val pairs = for {
  i <- Stream.from(1).takeWhile(_ < 3) 
  j <- Stream.from(1).takeWhile(_ < 3) 
}    
yield (i, j)

但出于问题的目的,想象一个更复杂的用例,其中流终止条件无法轻松移动到流表达式本身。

最佳答案

一种可能是将 Stream 包装到您自己的类中,该类以不同的方式处理 filter,在本例中为 takeWhile:

import scala.collection._
import scala.collection.generic._

class MyStream[+A]( val underlying: Stream[A] ) {
  def flatMap[B, That](f: (A) => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = underlying.flatMap(f);

  def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = underlying.map(f);

  def filter(p: A => Boolean): Stream[A] = underlying.takeWhile(p);
  //                                       ^^^^^^^^^^^^^^^^^^^^^^^^
}

object MyStream extends App {
  val pairs = for {
    i <- new MyStream(Stream.from(1))
    if i < 3
    j <- new MyStream(Stream.from(1))
    if j < 3
  } yield (i, j);

  print(pairs.toList);
}

这会打印List((1,1), (1,2), (2,1), (2,2))

关于scala - Scala 中无限流的嵌套迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14026617/

相关文章:

java - Akka 2.3.6 中缺少 IOManager

scala - 为什么Scala 中的这个函数调用没有被优化掉?

c - 按字符读取流字符

c++ - 运算符<<不匹配

使用 for-composition 解决 nQueen 的 Scala 解决方案

Scala 的要么元组为 Right

scala - Scala XML 属性的空检查

java - 为什么我不能从 Package Explorer 运行所有 Java JUnit 测试? - Scala 插件问题

racket - Racket 中的 for/list 与自定义 for/bytes

html - 使用HTML5 <audio>标记时,浏览器在页面刷新时将RST发送到shoutcast流