Question

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.

Was it helpful?

Solution

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?

OTHER TIPS

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)

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.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top