Combine two options [duplicate] - scala

Is there a predefined function x in Scala that combine 2 Options so that
Some(a) x None => Some(a)
None x Some(b) => Some(b)
None x None => None

Yes, this is the orElse method. It chooses the first defined value, or None if neither is defined.
scala> Some(1) orElse None
res0: Option[Int] = Some(1)
scala> None orElse Some(1)
res1: Option[Int] = Some(1)
scala> None orElse None
res2: Option[Nothing] = None
scala> Some(1) orElse Some(2)
res3: Option[Int] = Some(1)

It's not hard to do it by hand:
scala> val a = Some(1)
a: Some[Int] = Some(1)
scala> val b = Some(2)
b: Some[Int] = Some(2)
scala> Seq(a,b).flatten.headOption
res0: Option[Int] = Some(1)

In the question comments, you mention you can't have Some(a) and Some(b), so what you really have is Option[Either[Int,Int]]. In that case, you can use x.map(_.merge) to get back to Option[Int], eg
scala> val x:Option[Either[Int,Int]] = Some(Left(2))
x: Option[Either[Int,Int]] = Some(Left(2))
scala> x.map(_.merge)
res0: Option[Int] = Some(2)

Related

"Or"-ing two Options in Scala?

I want to do something like this:
def or[A](x: Option[A], y: Option[A]) = x match {
case None => y
case _ => x
}
What is the idiomatic way to do this? The best I can come up with was Seq(x, y).flatten.headOption
It's already defined for Option:
def or[A](x: Option[A], y: Option[A]) = x orElse y
in scalaz, you can use the Plus typeclass for this:
scala> 1.some <+> 2.some
res1: Option[Int] = Some(1)
scala> none[Int] <+> 2.some
res2: Option[Int] = Some(2)
scala> none[Int] <+> none[Int]
res3: Option[Int] = None
If, for some reason, you don't want to use orElse, well, there's always another way to do it in Scala.
def or[A](xOpt: Option[A], yOpt: Option[A]) = xOpt.map(Some(_)).getOrElse(yOpt)

Canonical way to work on Option elements in Scala

As an example, I want to apply a function f: (Int,Int) => Int to two elements of type Option[Int]. My thoughts were something like (a,b).zipped.map(f), but this yields a List, and I want to get a new Option[Int] as result.
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> (x,y).zipped.map(f)//I want None as a result here
res7: Iterable[Int] = List()
How can this be done without explicitly branching?
Just like many other operations in scala this can be done via for comprehension:
def f(a:Int,b:Int) = a*b
for (x <- maybeX; y <- maybeY) yield f(x, y)
As often is the case with this type of question, scalaz has some help:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> ^(x,y)(f)
res0: Option[Int] = None
scala> val x = 42.some
x: Option[Int] = Some(42)
scala> (x |#| y)(f)
res3: Option[Int] = None
Using om-nom-nom's idea, I can do something like this:
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> def lifted(f: (Int,Int) => Int) = (a:Option[Int],b:Option[Int]) => for(x<-a;y<-b) yield f(x,y)
lifted: (f: (Int, Int) => Int)(Option[Int], Option[Int]) => Option[Int]
scala> def liftedF = lifted(f)
liftedF: (Option[Int], Option[Int]) => Option[Int]
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> liftedF(x,x)
res0: Option[Int] = Some(1764)
scala> liftedF(x,y)
res2: Option[Int] = None
We can even generalize this...please cover your eyes:
def lift2[A, B, C](f: (A, B) => C): (Option[A], Option[B]) => Option[C] = (a: Option[A], b: Option[B]) =>
for (x <- a; y <- b) yield f(x, y)

Combining 2 Options into 1

Is there a predefined function x in Scala that combine 2 Options so that
Some(a) x None => Some(a)
None x Some(b) => Some(b)
None x None => None
Yes, this is the orElse method. It chooses the first defined value, or None if neither is defined.
scala> Some(1) orElse None
res0: Option[Int] = Some(1)
scala> None orElse Some(1)
res1: Option[Int] = Some(1)
scala> None orElse None
res2: Option[Nothing] = None
scala> Some(1) orElse Some(2)
res3: Option[Int] = Some(1)
It's not hard to do it by hand:
scala> val a = Some(1)
a: Some[Int] = Some(1)
scala> val b = Some(2)
b: Some[Int] = Some(2)
scala> Seq(a,b).flatten.headOption
res0: Option[Int] = Some(1)
In the question comments, you mention you can't have Some(a) and Some(b), so what you really have is Option[Either[Int,Int]]. In that case, you can use x.map(_.merge) to get back to Option[Int], eg
scala> val x:Option[Either[Int,Int]] = Some(Left(2))
x: Option[Either[Int,Int]] = Some(Left(2))
scala> x.map(_.merge)
res0: Option[Int] = Some(2)

List of options: equivalent of sequence in Scala?

What is the equivalent of Haskell's sequence in Scala? I want to turn list of options into an option of list. It should come out as None if any of the options is None.
List(Some(1), None, Some(2)).??? --> None
List(Some(1), Some(2), Some(3)).??? --> Some(List(1, 2, 3))
Scalaz defines sequence.
Here's an example:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> List(Some(1), None, Some(2)).sequence
res0: Option[List[Int]] = None
scala> List(some(1), some(2), some(3)).sequence
res1: Option[List[Int]] = Some(List(1, 2, 3))
Note that in the second example, you have to use Scalaz's some function to create a Some -- otherwise, the List is constructed as List[Some[Int]], which results in this error:
scala> List(Some(1), Some(2), Some(3)).sequence
<console>:14: error: could not find implicit value for parameter n: scalaz.Applicative[N]
List(Some(1), Some(2), Some(3)).sequence
The Scalaz some(a) and none functions create Some and None values of type Option[A].
If you want a solution for just List and Option rather a general monad then following will do the job,
def sequence[T](l : List[Option[T]]) =
if (l.contains(None)) None else Some(l.flatten)
REPL session,
scala> sequence(List(Some(1), None, Some(2)))
res2: Option[List[Int]] = None
scala> sequence(List(Some(1), Some(2), Some(3)))
res3: Option[List[Int]] = Some(List(1, 2, 3))
Update 20/8/2014
Just use Scalaz ...
Here is the same function as above using a combination of foldRight and map/ flatmap that only has to traverse the list once:
def sequence[A](lo: List[Option[A]]): Option[List[A]] =
lo.foldRight (Option(List[A]())) { (opt, ol) =>
ol flatMap (l => opt map (o => o::l))
}
Or, if you prefer the for comprehension version:
def sequence2[A](lo: List[Option[A]]): Option[List[A]] =
lo.foldRight (Option(List[A]())) { (opt, ol) =>
for {l <- ol; o <- opt} yield (o::l)
}
First off, I recommend that you check out the API docs for List.
As for a solution, this may not be the most graceful way to do it, but it'll work (and with no external dependencies):
// a function that checks if an option is a None
def isNone(opt:Option[_]) = opt match {
case None => true
case _ => false
}
//templated for type T so you can use whatever Options
def optionifyList[T](list:List[Option[T]]) = list.exists(isNone) match {
case true => None
case false => Some(list.flatten)
}
And a test just to be sure...
scala> val hasNone = Some(1) :: None :: Some(2) :: Nil
hasNone: List[Option[Int]] = List(Some(1), None, Some(2))
scala> val hasSome = Some(1) :: Some(2) :: Some(3) :: Nil
hasSome: List[Some[Int]] = List(Some(1), Some(2), Some(3))
scala> optionifyList(hasSome)
res2: Option[List[Int]] = Some(List(1, 2, 3))
scala> optionifyList(hasNone)
res3: Option[List[Int]] = None
Maybe this helps, as it traverses once only and use recursion
def sequence[A](a: List[Option[A]]): Option[List[A]] =
a match {
case Nil => Some(Nil)
case h :: rest => h.flatMap(x => sequence(rest).map(x :: _))
}
This is very simple with a for comprehension:
val x : Option[String] = Option("x")
val y : Option[String] = Option("y")
val z : Option[String] = None
// Result -> a: Option[List[String]] = None
val a = for {
x <- x
y <- y
z <- z
} yield List(x,y,z)
// Result -> b: Option[List[String]] = Some(List(x, y))
val b = for {
x <- x
y <- y
} yield List(x,y)
Since you need to flatten anyway, just do it first...
def sequence(lo: List[Option[A]]): Option[List[A]] = lo.flatten match {
la: List[A] if(la.length == lo.length) => Some(la)
_ => None
}
tail recursion might be quickest

Scala: map with two or more Options

Basically I'm looking for the most scala-like way to do the following:
def sum(value1: Option[Int], value2: Option[Int]): Option[Int] =
if(value1.isDefined && value2.isDefined) Some(value1.get + value2.get)
else if(value1.isDefined && value2.isEmpty) value1
else if(value1.isEmpty && value2.isDefined) value2
else None
This gives correct output:
sum(Some(5), Some(3)) // result = Some(8)
sum(Some(5), None) // result = Some(5)
sum(None, Some(3)) // result = Some(3)
sum(None, None) // result = None
Yet to sum more than two options I'd have to use way too many ifs or use some sort of loop.
EDIT-1:
While writing the question I came up with sort of an answer:
def sum2(value1: Option[Int], value2: Option[Int]): Option[Int] =
value1.toList ::: value2.toList reduceLeftOption { _ + _ }
This one looks very idiomatic to my inexperienced eye. This would even work with more than two values. Yet is possible to do the same without converting to lists?
EDIT-2:
I ended up with this solution (thanks to ziggystar):
def sum(values: Option[Int]*): Option[Int] =
values.flatten reduceLeftOption { _ + _ }
EDIT-3:
Another alternative thanks to Landei:
def sum(values: Option[Int]*): Option[Int] =
values collect { case Some(n) => n } reduceLeftOption { _ + _ }
How about:
scala> def sum(values: Option[Int]*): Option[Int] = values.flatten match {
| case Nil => None
| case l => Some(l.sum)
| }
sum: (values: Option[Int]*)Option[Int]
scala> sum(Some(1), None)
res0: Option[Int] = Some(1)
scala> sum(Some(1), Some(4))
res1: Option[Int] = Some(5)
scala> sum(Some(1), Some(4), Some(-5))
res3: Option[Int] = Some(0)
scala> sum(None, None)
res4: Option[Int] = None
Edit
Maybe it would be sane to return 0 if all arguments were None. In that case the function would reduce to values.flatten.sum.
scala> def sum(a: Option[Int], b: Option[Int]) = (a,b) match {
| case (Some(x), Some(y)) => Some(x + y)
| case (Some(x), None) => Some(x)
| case (None, Some(y)) => Some(y)
| case _ => None
| }
sum: (a: Option[Int],b: Option[Int])Option[Int]
scala> sum(Some(5), Some(3))
res0: Option[Int] = Some(8)
scala> sum(Some(5), None)
res1: Option[Int] = Some(5)
scala> sum(None, Some(3))
res2: Option[Int] = Some(3)
scala> sum(None, None)
res3: Option[Int] = None
Another solution is:
def sum(values: Option[Int]*): Int = values.collect{case Some(n) => n}.sum
While in the current case flatten is clearly more convenient, the collect version is more flexible, as it allows to perform mappings and to have additional filter conditions or complex patterns. E.g. imagine you want to have the sum of the squares of all even numbers in values:
values.collect{case Some(n) if n mod 2 == 0 => n*n}.sum
You can make it very concise using the fact that there is an Semigroup instance for Option that does exactly what you want. You can use scalaz or cats. Here is an example using cats:
import cats.std.option._
import cats.syntax.semigroup._
import cats.std.int._
Option(1) |+| Option(2) // Some(3)
Option(1) |+| None // Some(1)
None |+| Option(2) // Some(2)
So your sum becomes:
def sum(v1: Option[Int], v2: Option[Int]): Option[Int] = v1 |+| v2
Reduced solution of michael.kebe with a little look to some basic mathematical rules:
def sum(a: Option[Int], b: Option[Int]) = (a,b) match {
case (None,None) => None
case _ => Some(a.getOrElse(0)+b.getOrElse(0))
}
scala> sum(Some(5), Some(3)) // result = Some(8)
res6: Option[Int] = Some(8)
scala> sum(Some(5), None) // result = Some(5)
res7: Option[Int] = Some(5)
scala> sum(None, Some(3)) // result = Some(3)
res8: Option[Int] = Some(3)
scala> sum(None, None) // result = None
res9: Option[Int] = None