繁体   English   中英

在Scala中编写Streams上的操作

[英]Composing Operations on Streams in Scala

假设您有一个程序以某种方式操纵流Stream[Foo]以产生感兴趣的计算,例如

myFooStream.map(toBar).groupBy(identity).mapValues(_.size)

可爱,除了你现在必须在myFooStream上做一些其他类型的计算

myFooStream.map(toBar).sum

并且您希望以某种方式组合这些计算,这样您就不需要在流上迭代两次(假设由于某种原因迭代流是昂贵的)。

是否有一些Scala-ish方法来处理这个问题? 更抽象的是,我的问题是,我想以某种方式从这些流上的迭代中抽象出这些流的计算。 也就是说,最好的是如果我能以某种方式编写两个方法f: Stream[Foo] => Barg: Stream[Foo] => Baz并以某种方式组合fg ,使得它们在单次迭代中运行的流。

是否有一些抽象允许这个?

更新的问题:我做了一点挖掘。 scalaz箭头会对这个问题有帮助吗?

如果可能的话, Streams会自然地尝试通过记忆结果来避免多次生成元素。 来自文档

Stream类还使用memoization,使得先前计算的值从Stream元素转换为A类型A具体值。

我们可以看到,通过构造一个Stream ,每次生成元素时都会打印,并运行多个操作:

val stream = Stream.from(0).map(x => { println(x); x }).take(10) //prints 0
val double = stream.map(_ * 2).take(5).toList //prints 1 through 4
val sum = stream.sum //prints 5 through 9
val sum2 = stream.sum //doesn't print any more

只要您使用val而不是def这就有效:

只要有东西抓住头部,头部就会抓住尾巴,所以它会继续递归。 另一方面,如果没有任何东西保持头部(例如我们使用def来定义Stream ),那么一旦它不再被直接使用,它就会消失。

这个memoization意味着必须谨慎使用Streams

一个人必须谨慎记忆; 如果你不小心,你可以很快吃掉大量的记忆。 这样做的原因是Stream的memoization创建了一个与scala.collection.immutable.List非常相似的结构。

当然,如果项目的生成不是很昂贵的,但是实际遍历Stream或者memoization是不可用的,因为它太贵了,可以总是使用foldLeft和一个元组,跟踪多个值:

//Only prints 0-9 once, even if stream is a def
val (sum, double) = stream.foldLeft(0 -> List.empty[Int]) { 
    case ((sum, list), next) => (sum + next, list :+ (next * 2)) 
}

如果这是一个足够普通的操作,你甚至可以丰富Stream以进行一些更常见的操作,如foldLeftreduceLeft和其他以这种格式提供的操作:

implicit class RichStream[T](val stream: Stream[T]) extends AnyVal {
    def doubleFoldLeft[A, B](start1: A, start2: B)(f: (A, T) => A, g: (B, T) => B) = stream.foldLeft(start1 -> start2) { 
        case ((aAcc, bAcc), next) => (f(aAcc, next), g(bAcc, next)) 
    }
}

这将允许你做的事情,如:

val (sum, double) = stream.doubleFoldLeft(0, List.empty[Int])(_ + _, _ :+ _)

流不会迭代两次:

Stream.continually{println("bob"); 1}.take(4).map(v => v).sum
bob
bob
bob
bob
4

val bobs = Stream.continually{println("bob"); 1}.take(4)
val alices = Stream.continually{println("alice"); 2}.take(4)
bobs.zip(alices).map{ case (b, a) => a + b}.sum
bob
bob
bob
bob
alice
alice
alice
alice
12

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM