This question is the opposite of this question.
val x = Some((1, 2))
val (y: Option[Int], z: Option[Int]) = ???
Both pure Scala answers and Scalaz anwers are helpful.
This question is the opposite of this question.
val x = Some((1, 2))
val (y: Option[Int], z: Option[Int]) = ???
Both pure Scala answers and Scalaz anwers are helpful.
I actually think your answer is perfectly clear, but since you mention Scalaz, this operation is called unzip
:
scala> import scalaz._, std.option._
import scalaz._
import std.option._
scala> val x: Option[(Int, Int)] = Some((1, 2))
x: Option[(Int, Int)] = Some((1,2))
scala> Unzip[Option].unzip(x)
res0: (Option[Int], Option[Int]) = (Some(1),Some(2))
You should be able to write simply x.unzip
, but unfortunately the standard library's horrible implicit conversion from Option
to Iterable
will kick in first and you'll end up with an (Iterable[Int], Iterable[Int])
.
Looking back a year later: it's actually possible to do this with Scalaz's UnzipPairOps
:
scala> import scalaz.std.option._, scalaz.syntax.unzip._
import scalaz.std.option._
import scalaz.syntax.unzip._
scala> val x: Option[(Int, Int)] = Some((1, 2))
x: Option[(Int, Int)] = Some((1,2))
scala> x.unfzip
res0: (Option[Int], Option[Int]) = (Some(1),Some(2))
What were you thinking, 2014 me?
As per Jim's answer, but with a syntax that some may find easier to read:
val x = Some(1 -> 2)
val (y, z) = x map {case (a,b) => Some(a) -> Some(b)} getOrElse (None -> None)
The best I could come up with is the following, but it looks goofy to me:
val x = Some((1, 2))
val (y, z) = x map {x => (Some(x._1), Some(x._2)) } getOrElse (None, None)
As suggested by Rob Norris on the cats gitter channel, you can do this with cats by calling .separate
:
@ import cats.implicits._
import cats.implicits._
@ val x: Option[(Int, Int)] = Some((1, 2))
x: Option[(Int, Int)] = Some((1, 2))
@ x.separate
res6: (Option[Int], Option[Int]) = (Some(1), Some(2))
The type annotation in the assignment to x
is relevant; the implicit operates on Option
not on Some
:
@ val x = Some((1, 2))
x: Some[(Int, Int)] = Some((1, 2))
@ x.separate
cmd2.sc:1: value separate is not a member of Some[(Int, Int)]
val res2 = x.separate
separate
is provided by cats.MonadCombine
Starting Scala 2.13
, this exact behavior is provided in the standard library by Option#unzip
:
// val x: Option[(Int, String)] = Some(1, "hello")
x.unzip
// (Some(1), Some("hello"))
val (y, z) = x.unzip
// y: Option[Int] = Some(1)
// z: Option[String] = Some("hello")
// val x: Option[(Int, String)] = None
x.unzip
// (None, None)
Also note the equivalent for 3-element tuples: Option#unzip3
.