I have the following class:
case class Profile(email: Option[String],
firstName: Option[String],
lastName: Option[String],
fullName: Option[String])
Now I want to remove the fullName
attribute because it's redundant. However, I have a method in my class User
which returns the fullName
:
case class User(id: UUID, profiles: List[Profile]) {
// Skipped some lines
def fullName(loginInfo:LoginInfo) = profileFor(loginInfo).flatMap(_.fullName)
}
Now I am trying to replace the .flatMap(_.fullName)
part with a concatenation of firstName
+ lastName
. How can this be done? Do I need make a new Option[String]
, like this:
def fullName(loginInfo:LoginInfo) = {
val firstName = profileFor(loginInfo).flatMap(_.firstName)
val lastName = profileFor(loginInfo).flatMap(_.lastName)
val fullName : Option[String] = Some(firstName + " " + lastName)
fullName
}
Here's one approach
List(firstName, lastName).flatten match {
case Nil => None
case xs => Some(xs.mkString(" "))
}
quick testing in the REPL...
scala> def fullName(fn: Option[String], ln: Option[String]): Option[String] = {
| List(fn, ln).flatten match {
| case Nil => None
| case xs => Some(xs.mkString(" "))
| }
| }
fullName: (fn: Option[String], ln: Option[String])Option[String]
scala> fullName(None, None)
res3: Option[String] = None
scala> fullName(Some("a"), None)
res4: Option[String] = Some(a)
scala> fullName(None, Some("b"))
res5: Option[String] = Some(b)
scala> fullName(Some("a"), Some("b"))
res6: Option[String] = Some(a b)
I think that's a good application of a for
.
case class User(id: UUID, profiles: List[Profile]) {
// Skipped some lines
def fullName(loginInfo:LoginInfo): Option[String] = for {
profile <- profileFor(loginInfo)
first <- profile.firstName
last <- profile.lastName
} yield s"$first $last"
}
We can treat Option
as a collection and get what you're looking for in a simple one-liner:
val firstName: Option[String] = Some("John")
val lastName: Option[String] = Some("Doe")
val fullName: Option[String] = (firstName ++ lastName).reduceOption(_ + " " + _) // Some("John Doe")
map2
(see chapter 4 of "the red book") affords you some abstraction:
def map2[A, B, C](oa: Option[A], ob: Option[B])(f: (A, B) => C): Option[C] =
for {
a <- oa
b <- ob
} yield f(a, b)
Then, leaving the LoginInfo
stuff out (because you didn't define profileFor
anywhere), you can simply define fullName
as
def fullName: Option[String] = map2(firstName, lastName) { _ + " " + _ }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With