2011-08-09 19 views
12

在Python,我可以做這樣的事情:斯卡拉的理解何時是懶惰的?

lazy = ((i,j) for i in range(0,10000) for j in range(0,10000)) 
sum((1 for i in lazy)) 

這將需要一段時間,但內存使用是恆定的。

同樣的結構中階:

(for(i<-0 to 10000; j<-i+1 to 10000) yield (i,j)).count((a:(Int,Int)) => true)

一段時間後,我得到一個java.lang.OutOfMemoryError,即使它應該懶洋洋地評估。

回答

22

沒有什麼天生的懶惰關於斯卡拉的理解;它是語法糖*,它不會改變你的兩個範圍的組合會急切的事實。

如果你懶view是你的範圍內的工作,理解的結果將是懶惰太:

scala> for(i<-(0 to 10000).view; j<-(i+1 to 10000).view) yield (i,j) 
res0: scala.collection.SeqView[(Int, Int),Seq[_]] = SeqViewN(...) 

scala> res0.count((a: (Int, Int)) => true) 
res1: Int = 50005000 

這裏的懶惰是無關的換理解,但因爲當flatMap或在某些類型的容器上調用了map(請參見下文),則會在相同類型的容器中返回結果。所以,換理解只會保留懶惰(或缺乏),無論你放在


*這樣的事情:

(0 to 10000).flatMap(i => (i+1 to 10000).map(j => (i, j))) 
+0

「類似的東西」,但後者的表達似乎返回100020001元素,而不是50005000.威士忌探戈狐步舞? – Malvolio

+0

@Malvolio感謝您的注意! 'j'應該從'i + 1到10000',而不是'1到10000'。現在修復。 –

+0

D'oh。我應該注意到解決方案,而不僅僅是問題。我盯着地圖函數,忽略了參數.. – Malvolio

11

懶惰從換理解來未,但從收集本身。您應該考慮收集的嚴格特徵。

但是,對於懶惰的:-),這裏有一個總結:IteratorStream是非嚴格的,任何集合的view的選定方法也是如此。所以,如果你想懶惰,一定要先收藏.iterator,.view.toStream