0

我对 Scala 还是很陌生,我读到的其中一件事是,理解在某种程度上等同于 flatMap。但是,在我的代码(如下)中,flatMap 的计算时间至少是原来的两倍。这可能是什么原因?

这是慢的:

facts.flatMap(f => factActionsMap(f)).filter(_.isValid(facts))

这是快速等效的:

for {
  f <- facts
  a <- factActionsMap(f)
  if a.isValid(facts)
} yield a

factActionsMapFact是和之间的映射Set[Action]facts只是一个Set[Fact]

4

2 回答 2

8

让我们检查一下翻译:

scala> trait Fact
defined trait Fact

scala> trait Action { def isValid(s: Set[Fact]): Boolean }
defined trait Action

scala> def facts: Set[Fact] = ???
facts: Set[Fact]

scala> def factActionsMap: Map[Fact, Set[Action]] = ???
factActionsMap: Map[Fact,Set[Action]]

scala> import scala.reflect.runtime.{universe => u}
import scala.reflect.runtime.{universe=>u}

scala> val expr = u reify {
     | for {
     |   f <- facts
     |   a <- factActionsMap(f)
     |   if a.isValid(facts)
     | } yield a
     | }
expr: reflect.runtime.universe.Expr[scala.collection.immutable.Set[Action]] = Expr[scala.collection.immutable.Set[Action]]($read.f
acts.flatMap(((f) => $read.factActionsMap.apply(f).withFilter(((a) => a.isValid($read.facts))).map(((a) => a))(Set.canBuildFrom)))
(Set.canBuildFrom))

scala> u show expr.tree
res0: String = $read.facts.flatMap(((f) => $read.factActionsMap.apply(f).withFilter(((a) => a.isValid($read.facts))).map(((a) => a
))(Set.canBuildFrom)))(Set.canBuildFrom)

因此,删除 REPL 内容(所有以 开头的内容$)和隐式参数,再加上重新格式化,我们得到:

facts.flatMap(f => factActionsMap(f).withFilter(a => a.isValid(facts)).map(a => a))

这和你想出的有两个主要区别。首先,withFilter应用于fastActionsMap(f)结果,而您应用于facts.flatMap结果。这意味着flatMap将适用于所有结果,而不仅仅是接受的结果。

其次,它使用withFilter而不是filter,这避免了创建额外的集合。

于 2013-12-08T20:05:39.120 回答
1

除非我弄错了,否则更精确地等价于第二个表达式将是

facts.flatMap(f => factActionsMap(f).withFilter(_.isValid(facts)))

withFilter就像过滤器,除了它是惰性的,所以如果你没有对 Set 的内容做任何事情,你实际上并没有应用过滤器。例如,您可以通过在第二次调用 System.currentTimeMillis 之前打印集合的所有元素来检查这个假设。

于 2013-12-08T19:45:13.203 回答