簡體   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