I have the following function in Scala:
object TestFutures5 extends App {
def future (i:Int) = Future { i * 10 }
var rnd = scala.util.Random
val futureResult = (1 to 10).map {
x =>
val y = rnd.nextInt(x)
(future(x),y) // <- this should return a future
// as it needs to be processed by Future.sequence
}
Future.sequence(futureResult).foreach(list => println(list)) // <- this does not compile
Thread.sleep(5000)
}
In Future.sequence function I need to have access to the result of future(x) and to each variable y, but since sequence works only with futures this code does not compile. How to refactor/fix it?
You could just add y to the result of the future:
future(x).map(res => (res, y))
Your sequence will now contain a list of tuples with the result and the value of y
use traverse
Future.traverse(futureResult)(pair => pair._1.map(result => (pair._2, result)))
map each future so that the result will have y value.
Future.traverse(futureResult)(pair => pair._1.map(result => (pair._2, Right(result))).recover { case th => (pair._2, Left(th)) })
To get the y value in case of failure use recover.
So, to summarize it. You are using y as a tag or index for your future computation so that you can know what future with tag failed.
y works as a tag or name to the future.
Scala REPL
scala> Future.traverse(futureResult)(pair => pair._1.map(result => (pair._2, Right(result))).recover { case th => (pair._2, Left(th)) })
result: scala.concurrent.Future[scala.collection.immutable.IndexedSeq[(Int, scala.util.Either[Throwable,Int])]] = Future(<not completed>)
Related
I'm using pattern matching in scala a lot. Many times I need to do some calculations in guard part and sometimes they are pretty expensive. Is there any way to bind calculated values to separate value?
//i wan't to use result of prettyExpensiveFunc in body safely
people.collect {
case ...
case Some(Right((x, y))) if prettyExpensiveFunc(x, y) > 0 => prettyExpensiveFunc(x)
}
//ideally something like that could be helpful, but it doesn't compile:
people.collect {
case ...
case Some(Right((x, y))) if {val z = prettyExpensiveFunc(x, y); y > 0} => z
}
//this sollution works but it isn't safe for some `Seq` types and is risky when more cases are used.
var cache:Int = 0
people.collect {
case ...
case Some(Right((x, y))) if {cache = prettyExpensiveFunc(x, y); cache > 0} => cache
}
Is there any better solution?
ps: Example is simplified and I don't expect anwers that shows that I don't need pattern matching here.
You can use cats.Eval to make expensive calculations lazy and memoizable, create Evals using .map and extract .value (calculated at most once - if needed) in .collect
values.map { value =>
val expensiveCheck1 = Eval.later { prettyExpensiveFunc(value) }
val expensiveCheck2 = Eval.later { anotherExpensiveFunc(value) }
(value, expensiveCheck1, expensiveCheck2)
}.collect {
case (value, lazyResult1, _) if lazyResult1.value > 0 => ...
case (value, _, lazyResult2) if lazyResult2.value > 0 => ...
case (value, lazyResult1, lazyResult2) if lazyResult1.value > lazyResult2.value => ...
...
}
I don't see a way of doing what you want without creating some implementation of lazy evaluation, and if you have to use one, you might as well use existing one instead of rolling one yourself.
EDIT. Just in case you haven't noticed - you aren't losing the ability to pattern match by using tuple here:
values.map {
// originial value -> lazily evaluated memoized expensive calculation
case a # Some(Right((x, y)) => a -> Some(Eval.later(prettyExpensiveFunc(x, y)))
case a => a -> None
}.collect {
// match type and calculation
...
case (Some(Right((x, y))), Some(lazyResult)) if lazyResult.value > 0 => ...
...
}
Why not run the function first for every element and then work with a tuple?
Seq(1,2,3,4,5).map(e => (e, prettyExpensiveFunc(e))).collect {
case ...
case (x, y) if y => y
}
I tried own matchers and effect is somehow OK, but not perfect. My matcher is untyped, and it is bit ugly to make it fully typed.
class Matcher[T,E](f:PartialFunction[T, E]) {
def unapply(z: T): Option[E] = if (f.isDefinedAt(z)) Some(f(z)) else None
}
def newMatcherAny[E](f:PartialFunction[Any, E]) = new Matcher(f)
def newMatcher[T,E](f:PartialFunction[T, E]) = new Matcher(f)
def prettyExpensiveFunc(x:Int) = {println(s"-- prettyExpensiveFunc($x)"); x%2+x*x}
val x = Seq(
Some(Right(22)),
Some(Right(10)),
Some(Left("Oh now")),
None
)
val PersonAgeRank = newMatcherAny { case Some(Right(x:Int)) => (x, prettyExpensiveFunc(x)) }
x.collect {
case PersonAgeRank(age, rank) if rank > 100 => println("age:"+age + " rank:" + rank)
}
https://scalafiddle.io/sf/hFbcAqH/3
I want to count up the number of times that a function f returns each value in it's range (0 to f_max, inclusive) when applied to a given list l, and return the result as an array, in Scala.
Currently, I accomplish as follows:
def count (l: List): Array[Int] = {
val arr = new Array[Int](f_max + 1)
l.foreach {
el => arr(f(el)) += 1
}
return arr
}
So arr(n) is the number of times that f returns n when applied to each element of l. This works however, it is imperative style, and I am wondering if there is a clean way to do this purely functionally.
Thank you
how about a more general approach:
def count[InType, ResultType](l: Seq[InType], f: InType => ResultType): Map[ResultType, Int] = {
l.view // create a view so we don't create new collections after each step
.map(f) // apply your function to every item in the original sequence
.groupBy(x => x) // group the returned values
.map(x => x._1 -> x._2.size) // count returned values
}
val f = (i:Int) => i
count(Seq(1,2,3,4,5,6,6,6,4,2), f)
l.foldLeft(Vector.fill(f_max + 1)(0)) { (acc, el) =>
val result = f(el)
acc.updated(result, acc(result) + 1)
}
Alternatively, a good balance of performance and external purity would be:
def count(l: List[???]): Vector[Int] = {
val arr = l.foldLeft(Array.fill(f_max + 1)(0)) { (acc, el) =>
val result = f(el)
acc(result) += 1
}
arr.toVector
}
In this code I need to print variable seq, but since it's printed before the futures are processed it is printed empty. How to wait for variable seq to be populated before the statement println(seq) is executed?
object TestFutures5 extends App {
def future (i:Int) = Future { i * 10 }
val seq = Seq[Int]()
for ( x <- 1 to 10 ) {
val future2 = future(x)
future2.map { y =>
println(y)
seq :+ y
}
}
println(seq) // <-- this always prints List()
Thread.sleep(5000)
}
The print statement must be executed after all the futures completed, which means that you need to store a reference to each created future. Your sequence is also immutable so you can not add elements to it. If you want to do this in without mutating variables your loop should be refactored like this:
val futureResult = (1 to 10).map {
x =>
future(x)
}
Then simply use Future.sequence to group the futures and do the print:
Future.sequence(futureResult).map(res => println(res))
What is the best way to go from
Map[String, Future[A]]
to
Map[String, A]
where A is the result of the corresponding future's execution?
This won't compile:
val results = for {
(key, future) <- myMap
result <- future
} yield (key, result)
as I can't mix futures and iterables in the same for comprehension.
If you convert it into a Seq[Future[(String,A)]], you can then use Future.fold to get it back a single Future[Map[...]]:
def transform[A](m: Map[String, Future[A]]): Future[Map[String, A]] = {
val seq: Seq[Future[(String, A)]] = m.toSeq.map { case (key, f) =>
f.map(i => key -> i)
}
Future.fold(seq)(Map.empty[String, A])(_ + _)
}
Then redeem the single future as normal.
Something like this perhaps:
map.mapValues { Await.result(_, 5 seconds) }
Dima already gave an answer using Await. However it will raise an exception when the Future fails.
You can further wrap the types inside as a Try and then do a .collect to filter only for the successful Futures (check out the official API for it).
import scala.util.{ Try, Success }
val results = myMap
.map {
case (key, value) => key => Try(Await.result(value, 5.seconds))
}
.collect {
case (key, Success(value)) => key -> value
}
With the call above, you automatically discard failing futures and only collect successful ones.
I have the following code:
// Start async functions
val async1: Future[Seq[Int]] = ...
val async2: Future[Seq[Int]] = ...
val async3: Future[Seq[Int]] = ...
// Wait for completion
(for {
a1 <- async1
a2 <- async2
a3 <- async3
} yield (a1, a2, a3)).map {
// Use the results
}
I want to improve this to handle a variable amount of async functions (and not necessarily calling each of them every time). What I have done so far is:
// Start the async functions ?
val asyncs: Seq[Future[Seq[Int]] = otherList.filter(x => someCondition).map(x => asyncFunc(x))
// Wait for the functions to finish ?
(for (seqInt <- asyncs) yield seqInt).map {
case results => // <-- problem here
// Use the results
}
The problem I am having is that the results are of type Future[Seq[Int]], but I expected they would be of type (Seq[Int], Seq[Int], Seq[Int]) like in the first snippet.
In the end I would like to do is kickoff a dynamic amount of async functions which all have the same Future return type, wait for them all to finish, then use all of their results together.
Future.sequence is the key part I was missing (thanks for the comment)
// Create a list of Futures
val asyncs: Seq[Future[Seq[Int]] = otherList.filter(x => someCondition).map(x => asyncFunc(x))
// Use Future.sequence to to execute them and return a list of sequence of integers
Future.sequence(asyncs).map{
case results => // Use the results List[Seq[Int]]
}.recover {
case error => // Oh no!
}