Reputation: 2115
I'd like to build a Map like this:
def one = "one"
def two = "two"
def three = Some("three")
Map[String, String]("one" -> one, "two" -> two, "three" -> three)
This won't compile because the method three returns an Option instead of a String. I can make this work like this:
Map[String, String]("one" -> one, "two" -> two) ++ three.map(t => Map("three" -> t)).getOrElse(Map.empty[String, String])
Now it will only add the Option to the list when it's Some.
But there must be a more elegant way. (lift-json for example knows how to filter out Options when constructing JValue's).
Any suggestions? (P.S. I've simplified the problem here)
Upvotes: 3
Views: 313
Reputation: 12852
In order to provide a nice interface to your clients, you could extend one of the Map
's to perform the unpacking:
class MyMap[A, B](private val tuples: (A, Option[B])*)
extends collection.DefaultMap[A, B] {
private val container =
new collection.mutable.HashMap[A, B]()
container ++= tuples collect {case (k, Some(v)) => (k, v)}
def iterator = container.iterator
def get(id: A) = container.get(id)
override def size = container.size
}
Combine this with an implicit that turns pairs (A, B)
into pairs (A, Option[B])
:
implicit def pairToPairWithSomeValue[A, B](t: (A, B)): (A, Option[B]) =
(t._1, Some(t._2))
And use it as:
def one = "one"
def two = "two"
def three = Some("three")
def four = None
val mm = new MyMap("one" -> one, "two" -> two, "three" -> three,
"four" -> four)
mm foreach println
/* (two,two), (one,one), (three,three) */
Upvotes: 0
Reputation: 167931
You have two kinds of map, e.g.:
val map1 = Map("one" -> 1, "two" -> 2)
val map2 = Map("three" -> Some(3), "four" -> None)
You can unpack the latter:
map2.collect { case (k,Some(v)) => (k,v) }
and merge the maps:
map1 ++ map2.collect{ case (k,Some(v)) => (k,v) }
Upvotes: 4
Reputation: 418
If you know which values are Options and which are not, you can simply call getOrElse
directly after the method call:
Map[String, String]("one" -> one, "two" -> two, "three" -> three.getOrElse("empty"))
If you don't know which methods will return an Option, you could use an implicit conversion to extract the value from the Option or set it to an default value if it is None
:
implicit def optToStr(a : Option[String]) : String = a.getOrElse("empty")
Map[String, String]("one" -> one, "two" -> two, "three" -> three)
You could also delete the default key-value pairs afterwards by using a filter on the map although this is not very elegant (perhaps somebody else knows a better solution in this case).
Upvotes: 2
Reputation: 92126
Map("one" -> one, "two" -> two) ++ three.map("three" -> _)
will work too.
Upvotes: 7