2013-05-26 60 views
3

從第一次讀的是:Scala的用於推導和flatMap /地圖中間結果

for { 
    harpo<-list1 if harpo.length>0 
    groucho<-list2 
    chico<-list3 
} yield (harpo, groucho, chico) 

轉換爲:

list1.filter(_.length>0).flatMap(harpo =>  
     list2.flatMap(groucho=>list3.map((harpo,groucho,_))) 
) 

我擔心由filter返回不必要的中間集合,flatMap & map。第一個通過添加withFilter方法在Scala 2.8(?)中得到修復,我懷疑有一些魔法會根據使用情況改變這些方法的返回類型,因此當用作參數flatMap時,嚴格收集,但我找不到任何證據。我的懷疑是否正確,並不像乍看起來那麼無效?

回答

4

這與this question有關。具體來說,通過the answer顯示@IODEV你如何看待脫糖形式:

$ scala -Xprint:typer -e 
'val list1 = List("foo", "bar"); val list2 = list1; val list3 = list1; 
for (harpo<-list1 if harpo.length>0; groucho <- list2; chico <- list3) 
yield (harpo, groucho, chico)' 

(不換行)

list1.withFilter(_.length() > 0) 
    .flatMap(harpo => 
    list2.flatMap(groucho => 
     list3.map(chico => (harpo, groucho, chico)) 
    ) 
) 

我看不出有任何浪費中間集合,你可以保存,除非你去一個可變的建設者和whileforeach來電填寫該建設者:

val b = List.newBuilder[(String, String, String)] 
for(harpo <- list1 if harpo.length() > 0; groucho <- list2; chico <- list3) { 
    b += ((harpo, groucho, chico)) 
} 
b.result() 

問題是,您的特定代碼是否表現出明顯的性能問題。例如。你的藏品非常大。如果不是,請使用更習慣的形式(for ... yield)。只有當你真正從中獲益時,纔會優化for ... {}

+0

也許我應該更清楚。我的問題是:在這種情況下,list3.map和list2.flatMap返回的集合是否嚴格?如果他們是嚴格的,那麼他們會被重複建造,以便在將他們的元素放入父集合後丟棄。如果我只是'val l = list3.map(「brother」+ _)'我得到一個嚴格的收集。在這種情況下,一個典型的C++模式是使用一個惰性中間類型,當它被分配給期望返回類型的變量時,它會隱式轉換爲嚴格類型。我不知道在scala中是否可能,但它的類型推斷對我來說仍然有祕密。 – Turin

+0

'list2'和'list3'可能是嚴格的(你沒有指定它們的類型,但是假設它們的類型是'List'),所以內部循環創建嚴格的中間結果。我不知道C++集合,但是我懷疑你可以用一種懶惰的方式嵌套'flatMaps',以消除任何中間集合 - __'map'__和__'filter'__是,但不是__'flatMap'__。如果你想要,使用builder和'foreach'的迭代方法。正如我所說,不要被過早的優化所困擾。 –