How to convert Future[Option[A]] to Future[A] - scala

I am new to Scala and wanted to know how can we convert Future[Option[A]] to Future[A]

Since an Option[A] might be None, if you want to convert it to an A, the most direct way is to use the .getOrElse(value) method, where you need to provide a default value of type A to use if the option itself doesn't have one.
val opt1 = Some(3)
opt1.getOrElse(5) //returns 3
val opt2 = None
opt2.getOrElse(5) //returns 5
Then, if you have a Future[Option[A]], you want to do this in the .map method of the future:
val futureOpt: Future[Option[Int]] = Future{ Some(3) }
val future: Future[Int] = futureOpt.map{opt => opt.getOrElse(5)}

An Option[A] can either be Some[A] or None. The Some[A] case is simple, you can just get A from it. But what about the None case, you can either provide a default value or consider it a failure.
Using a default value,
val aDefault: A = ...
val aFuture1 = aOptionFuture.map({
case Some(a) => a
case None => aDefault
})
// or
val aFuture2 = aOptionFuture.map(_.getOrElse(aDefault))
Consider a failure,
val aFuture3 = aOptionFuture.flatMap({
case Some(a) => Future.successful(a)
case None=> Future.failed(new Exception("computed a None"))
})

val optFuture: Future[Option[Int]] = Future(Some(3))
optFuture.map {
case Some(v) => v
case None => throw new RuntimeException("<some-exception>")
}
Or
optFuture.map(_.getOrElse(throw new RuntimeException("<some-exception>")))

Related

Link Multiple Either's

Consider the scenario
trait Checker {
def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]]
}
This trait is implemented by various class's.
Lets say
class CheckerImpl1 extends Checker {
override def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]] = ???
}
class CheckerImpl2 extends Checker {
override def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]] = ???
}
Now, I need to define a new function that will call check() function for each of these implementation classes in sequence(sequence does not matter) and return a new either i.e. Future[Either[String, Unit]] where String here is concatenated string of left for the check() implementation result.
So if CheckerImpl1.check() returns Left("error1") and CheckerImpl2.check() returns Left("error2") then result of the new function will return Left("error1&error2") (& just separate two strings).
OR
So if CheckerImpl1.check() returns Right(()) and CheckerImpl2.check() returns Left("error2") then result of the new function will return Left("error2").
OR
So if CheckerImpl1.check() returns Right(()) and CheckerImpl2.check() returns Right(()) then result of the new function will return Right(()).
What I have done right now is
(CheckerImpl1.check(), CheckerImpl2.check())
.mapN {
case (Right(_), Right(_)) => Right(())
case (Left(err), Right(_)) => Left(err)
case (Right(_), Left(err)) => Left(err)
case (Left(err1), Left(err2)) => Left(err1 ++ "&" ++ err2)))
}
But this is not a ideal solution, because if I add more implementation, then I would need to add more of these case statement.
Is there a better way of doing this ?
So you have a List of Future Eithers.
val lfe :List[Future[Either[String,Unit]]] = ???
To get all the Left strings together in one Future[String] you could do this...
val res :Future[String] =
Future.sequence(lfe)
.map(_.flatMap(_.fold(Some(_),_ => None)).mkString(" & "))
If I understand correctly, you eventually want to get Future[Either[String, Unit]] type. Why not just .sequence futures and .fold the results?
val checkers: List[Checker] = ???
Future.sequence(checkers.map(_.check()))
.map { results => results.foldLeft(Right(()): Either[String, Unit]) {
case (Left(acc), Left(err)) => Left(s"$acc&$err")
case (Right(_), Left(err)) => Left(err)
case (acc, Right(_)) => acc
}}
The only code change you need now is to augment checkers list.
Somewhat more elegant using cats (if you are not familiar with kind projector plugin - that's where the * comes from).
import cats.implicilts._
checkers.map(_.check()).sequence
.map { results =>
results.map(_.toValidatedNec)
.sequence[ValidatedNec[String, *], Unit]
.leftMap(_.toList.mkString("&"))
.map(_ => ())
.toEither
}

Short circuit Map Operation If Try Fails

I have a function like this:
def foo(item: Item) : Option[Int] = Try{
// Some code that can blow up
}.toOption
I have a list of items and I want to map through them, and apply the above function. But if the function above blows up and returns a None then the result of the map should be an error:
items.map{
item => foo(item)
}
Is map not the right thing to do here? It doesn't seem like it
This is called traverse. If you can use cats, it is as simple as:
import cats.implicits._
val result = items.traverse(foo) // Option[List[Int]]
If not, you can implement it pretty easily:
def traverse[A, B](data: List[A])(f: A => Option[B]): Option[List[B]] = {
#annotation.tailrec
def loop(remaining: List[A], acc: List[B]): Option[List[B]] =
remaining match {
case a :: as => f(a) match {
case Some(b) => loop(remaining = as, b :: acc)
case None => None
}
case Nil => Some(acc.reverse)
}
loop(remaining = data, acc = List.empty)
}
Which you can use like:
val result = traverse(items)(foo) // Option[List[Int]]
(however, I would suggest you to use cats instead, since it is more general).
For out-of-the-box short-circuiting, consider wrapping the list-mapping with Try like so
def fooUnsafe(item: Item): Int = // might throw
Try(items.map(fooUnsafe))
If you wish to keep def foo(item: Item) : Option[Int] signature then the following will also short-circuit
Try(list.map(v => foo(v).get))

Need to convert a Seq[Option[A]] to Option[Seq[A]]

USE CASE
I have a list of files that can might have a valid mime type or not.
In my code, I represent this using an Option.
I need to convert a Seq[Option[T]] to Option[Seq[T]] so that I do not process the list if some of the files are invalid.
ERROR
This is the error in the implementation below:
found : (Option[Seq[A]], Option[A]) => Option[Seq[A]]
[error] required: (Option[Any], Option[Any]) => Option[Any]
[error] s.fold(init)(liftOptionItem[A])
IMPLEMENTATION
def liftOptionItem[A](acc: Option[Seq[A]], itemOption: Option[A]): Option[Seq[A]] = {
{
acc match {
case None => None
case Some(items) =>
itemOption match {
case None => None
case Some(item) => Some(items ++ Seq(item))
}
}
}
}
def liftOption[A](s: Seq[Option[A]]): Option[Seq[A]] = {
s.fold(Some(Seq()))(liftOptionItem[A])
}
This implementation returns Option[Any] instead of Option[Seq[A] as the type of the liftOptionItem[A] does not fit in.
If you use TypeLevel Cats:
import cats.implicits._
List(Option(1), Option(2), Option(3)).traverse(identity)
Returns:
Option[List[Int]] = Some(List(1, 2, 3))
You have to use List so use a toList first:
Seq(Option(1), Option(2), Option(3)).toList.traverse(identity).map(_.toSeq)
using scalaz:
import scalaz._
import Sclaza._
val x:List[Option[Int]] = List(Option(1))
x.sequence[Option, Int] //returns Some(List(1))
val y:List[Option[Int]] = List(None, Option(1))
y.sequence[Option, Int] // returns None
If you dont want to use functional libraries like cats or Scalaz you could use a foldLeft
def seqToOpt[A](seq: Seq[Option[A]]): Option[Seq[A]] =
seq.foldLeft(Option(Seq.empty[A])){
(res, opt) =>
for {
seq <- res
v <- opt
} yield seq :+ v
}
Tail-recursive Solution: It returns None if any one of the seq element is None.
def seqToOption[T](s: Seq[Option[T]]): Option[Seq[T]] = {
#tailrec
def seqToOptionHelper(s: Seq[Option[T]], accum: Seq[T] = Seq[T]()): Option[Seq[T]] = {
s match {
case Some(head) :: Nil => Option(head +: accum)
case Some(head) :: tail => seqToOptionHelper(tail, head +: accum)
case _ => None
}
}
seqToOptionHelper(s)
}
Dealing with None in case statements is the reason for returning the Option[Seq[Any]] type in stead of Option[Seq[A]] type. We need to make the function
liftOptionItem[A] to return Option[Seq[Any]] type. And the compilation error can be fixed with the following changes in both the functions.(Because fold does not go in any particular order, there are constraints on the start value and thus return value , the foldLeft is used in stead of fold.)
def liftOptionItem[A](acc: Option[Seq[Any]], itemOption: Option[A]): Option[Seq[Any]] = {
{
acc match {
case None => Some(Nil)
case Some(items)=>
itemOption match {
case None => Some(items ++ Seq("None"))
case Some(item) => Some(items ++ Seq(item))
}
}
}
}
def liftOption[A](s: Seq[Option[A]]): Option[Seq[Any]] = {
s.foldLeft(Option(Seq[Any]()))(liftOptionItem[A])
}
Now, code compiles.
In Scala REPL:
scala> val list1 = Seq(None,Some(21),None,Some(0),Some(43),None)
list1: Seq[Option[Int]] = List(None, Some(21), None, Some(0), Some(43), None)
scala> liftOption(list1)
res2: Option[Seq[Any]] = Some(List(None, 21, None, 0, 43, None))
scala> val list2 = Seq(None,Some("String1"),None,Some("String2"),Some("String3"),None)
list2: Seq[Option[String]] = List(None, Some(String1), None, Some(String2), Some(String3), None)
scala> liftOption(list2)
res3: Option[Seq[Any]] = Some(List(None, String1, None, String2, String3, None))
There is no really "beautiful" way to make this with out scalaz or cats.
But you can try something like this.
def seqToOpt[A](seq: Seq[Option[A]]): Option[Seq[A]] = {
val flatten = seq.flatten
if (flatten.isEmpty) None
else Some(flatten)
}

Scala Tuple Option

If I have Scala tuple Option of the likes:
(Some(1), None)
(None, Some(1))
(None, None)
And I want always to extract always the "Some" value if it exists, and otherwise get the None. The only way with pattern matching?
There is this:
def oneOf[A](tup: (Option[A], Option[A])) = tup._1.orElse(tup._2)
That will return the first option that is defined, or None if neither is.
Edit:
Another way to phrase the same thing is
def oneOf[A](tup: (Option[A], Option[A])) =
tup match { case (first, second) => first.orElse(second) }
It's longer, but perhaps more readable.
This should work:
def f(t: (Option[Int], Option[Int])): Option[Int] = t match {
case (Some(n), _) => Some(n)
case (_, Some(n)) => Some(n)
case _ => None
}
I want always to extract always the Some value if it exists, and otherwise get the None
You can just use orElse
def orOption[T](p: (Option[T], Option[T])): Option[T] = {
val (o1, o2) = p
o1 orElse o2
}
However, this does decide what to do if there exists two Some values:
scala> orOption((Some(1), Some(2)))
res0: Option[Int] = Some(1)
You should probably use pattern matching and then decide what to do if there are two Some values, like throw an exception. Alternatively, consider using a better encoding for the result type than Option.

Extract Value from nested options

What is the most concise way to get 10 out of Some(Some(Some(Some(10))))?
without resorting to some external library like Scalaz.
import scala.language.higherKinds
case class Flattener[W[_], WW, T](fn : WW => W[T])
implicit def optionRecFlattenFn[WW, T](
implicit f : Flattener[Option, WW, T] = Flattener((ww: WW) => Option(ww))
) = Flattener((ww : Option[WW]) => ww.flatMap(f.fn))
def optionRecursiveFlatten[WW, T](www : Option[WW])(
implicit f : Flattener[Option, Option[WW], T]
) = f.fn(www)
val nestedOption = Option(Option(Option(Option(10))))
// Some(Some(Some(Some(10))))
val flatOption = optionRecursiveFlatten(nestedOption)
// Some(10)
val evenMoreNestedOption = Option(Option(Option(Option(Option(Option(10))))))
// Some(Some(Some(Some(Some(Some(10))))))
val flatOption2 = optionRecursiveFlatten(evenMoreNestedOption)
// Some(10)
In case you don't know the nesting level in advance, this will work for any level:
def unwrapRec(o: Option[Any]) : Any = o match {
case Some(inner # Some(_)) => unwrapRec(inner)
case Some(x) => x
case _ => ???
}
However, please note that an Any is returned. You can change it to whatever type you like and adapt the pattern match accordingly but I think you will have to pass in an Option[Any]. So it's not typesafe at this point.
You can use flatten on nested Option[Option[A]] repeatedly:
scala> val a = Some(Some(Some(Some(10))))
a: Some[Some[Some[Some[Int]]]] = Some(Some(Some(Some(10))))
scala> a.flatten.flatten.flatten.get
res0: Int = 10
I do not think there is any generic and type-safe way to extract A from T[A] := Option[T[A]] | A.
Edit: This method can dynamically get the contents, returns either the innermost value, or None:
def unwrap(x: Any): Any = x match {
case Some(v) => unwrap(v)
case v => v
}
scala> unwrap(Some(Some(Some(Some(10)))))
res1: Any = 10
scala> unwrap(Some(None))
res2: Any = None
It has unfortunately too broad type: Any => Any.