Reputation: 317
I have
filepaths
)loadData
)I want to read the files only when we also need to calculate the statistics. The line below will loop over the filepaths, and returns its name and file contents.
for((name, path) <- filepaths) yield (name, loadData(path))
Is it possible to do such a for-comprehension for a LazyList
, so that the loadData
-part is evaluated lazily?
Upvotes: 1
Views: 688
Reputation: 4501
for comprehension
is just syntactic sugar for combinations of flatMap
and map
functions. You can do that you need just using map function:
def loadData(path: String): String = {
println(s"launch loadData on $path")
s"${path}_suffix"
}
val filePaths = Seq("p1" -> "path1", "p2" -> "path2")
val lazyList = filePaths.to(LazyList).map{
case (name, path) => name -> loadData(path)
}
println(lazyList)
println(lazyList.force)
// output will be:
//LazyList(<not computed>)
//launch loadData on path1
//launch loadData on path2
//LazyList((p1,path1_suffix), (p2,path2_suffix))
Here we see loadData
evaluates only when next element is needed.
Upvotes: 5
Reputation: 20611
It's most definitely possible.
for ((name, path) <- filepaths) yield (name, loadData(path))
Is just syntactic sugar for
filepaths.map { x =>
val (name, path) = x
(name, loadData(path)
}
(that may not be what the compiler actually desugars it to (I forget whether there would be multiple functions (one to extract the pairs and one to call loadData
) or not))
Since there's a map
on LazyList
, if filepaths
is a LazyList
it will work.
That said, it's not maximally lazy: getting the n
th entry requires evaluating the (n - 1)
th entry.
Of course, whenever you have a Seq[(A, B)]
(or Iterable[(A, B)]
/ Traversable[(A, B)]
), it's worth considering if what you really want is a Function1[A, B]
or a Map[A, B]
(which can just be thought of as an easy way to construct a subset of Function[A, B]
).
// assuming that filepaths is an `Iterable[(A, B)]`
filepaths.toMap.mapValues(loadData(_))
(Note that the (_)
might be able to be omitted).
This will be non-strict (it won't call loadData
until you lookup a given name
), but it won't be maximally lazy (there's no memoization: every lookup will result in a loadData
call). If you want maximal laziness, you'd have to implement your own memoization.
Upvotes: 1