2013-05-26 27 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'的迭代方法。正如我所说,不要被过早的优化所困扰。 –