-
-
Save kyrsideris/ceccce60d2a7002d6e15184579c563ed to your computer and use it in GitHub Desktop.
Gist that contains the code in https://sider.is/blog/post/scala-option-of-sequences
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// How to work with Options of Options of Sequences in Scala | |
type X = String | |
case class A(osx: Option[Seq[X]]) | |
case class B(oa: Option[A]) | |
val b = B( Some(A( Some(Seq("a1", "a2", "a3")) )) ) | |
// Task: given b, get the Seq[X] from A.osx | |
var xs: Seq[X] = ??? | |
// What to know: | |
Option(B).toSeq == Seq[B.type] // Option is like a list that might contain 1 or 0 elements | |
// Explanation: | |
// Option[B] { | |
// def toSeq: Seq[B] = { | |
// this match { | |
// case Some(b: B) => Seq[B](b) | |
// case None => Seq() | |
// } | |
// } | |
// } | |
// Approach 1 | |
// Work with Options through B to A and then getOrElse | |
xs = b.oa.flatMap(_.osx).flatMap(sx => Some(sx)).getOrElse(Nil) // or | |
xs = b.oa.flatMap(_.osx).flatMap(Some(_)).getOrElse(Nil) | |
// with types written down | |
xs = b // B | |
.oa // Option[A] | |
.flatMap[Seq[X]]( // Option[A].flatMap[Seq[X]] | |
a => a.osx // A => Option[Seq[X]] | |
) // Option[Seq[X]] | |
.flatMap[Seq[X]]( // Option[Seq[X]].flatMap[Seq[X]] | |
sx => Some(sx) // Seq[X] => Some[Seq[X]] | |
) // Option[Seq[X]] | |
.getOrElse[Seq[X]]( // Option[Seq[X]].getOrElse[Seq[X]] | |
Nil // default :=> Seq[X] | |
) // Seq[X] | |
// Learning point: This approach is easy to follow as it uses Options all the way but it is verbose | |
// Approach 2 | |
// Convert B.oa Option to Sequence, then apply a function in flatMap to get the A.osx | |
xs = b.oa.toSeq.flatMap(a => a.osx.toSeq.flatMap(sx => sx)) // or | |
xs = b.oa.toSeq.flatMap(a => a.osx.toSeq.flatten) // or | |
xs = b.oa.toSeq.flatMap(_.osx.toSeq.flatten) | |
// with types written down | |
xs = b // B | |
.oa // Option[A] | |
.toSeq // Seq[A] | |
.flatMap[X, Seq[X]]( // Seq[A].flatMap[X, Seq[X]] | |
a => // A => Seq[X] | |
a.osx // Option[Seq[X]] | |
.toSeq // Seq[Seq[X]] | |
.flatten[X] // Seq[Seq[X]].flatten[X] | |
) // Seq[X] | |
// Learning point: This approach is dealing only with Sequences | |
// but it complicates the conversion because it uses a deeper nested function | |
// Approach 3 | |
// Work with Options to get A.osx, convert to Seq of Seq and finally flatten it | |
xs = b.oa.flatMap(a => a.osx).toSeq.flatten // or | |
xs = b.oa.flatMap(_.osx).toSeq.flatten | |
// with types written down | |
xs = b // B | |
.oa // Option[A] | |
.flatMap[Seq[X]]( // Option[A].flatMap[Seq[X]] | |
a => a.osx // A => Option[Seq[X]] | |
) // Option[Seq[X]] | |
.toSeq // Seq[Seq[X]] | |
.flatten // Seq[X] | |
// Learning point: This approach is simpler and less verbose because it is handling | |
// Options to get the required field, smaller function in flatMap and less complicated types. | |
// Conclusion: Use options to reach the field, smaller functions in flatMap, | |
// and then finally Option to Sequence along with flattening to get the result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment