I've a question about the efficiency of for-comprehensions in scala.
This following code takes around 45 sec to run when perm is a list of around 550 elements
perm = some list
for{
perm <- perms.withFilter(_.size > 0)
wordList = somefunction(perm) //expensive operation, wordlist is a list of strings
sentenceList = somefunction1(perm) //very expensive operation, sentenceList is a list of list of strings
word <- wordList
sentence <- sentenceList
} yield { word::sentence}
When I changed the following code into the following, it ran in 3 sec with the same perm list
perm = some list
for{
perm <- perms.withFilter(_.size > 0)
word <- somefunction(perm) //expensive operation
sentence <- somefunction1(perm) //very expensive operation
} yield { word::sentence}
Does the difference in the performance has something to do with lazy evaluation in Scala?
Let's desugar both for-comprehensions:
1.)
perms.withFilter(_.size > 0).flatMap { perm =>
val wordList = somefunction(perm) //expensive operation
val sentenceList = somefunction1(perm) //very expensive operation
wordList.flatMap { word =>
sentenceList.map { sentence =>
word::sentence
}
}
}
2.)
perms.withFilter(_.size > 0).flatMap { perm =>
somefunction(perm).flatMap { word =>
somefunction1(perm).map { sentence =>
word :: sentence
}
}
}
In the first case, both expensive functions will be executed every time. In the second case, when somefunction(perm)
returns an empty result, somefunction1(perm)
will never be executed.