Reputation: 25
I'm trying to use Scala features as much as possible in my current project, but I have a hard time using pattern matching inside a Map definition.
To illustrate this, consider the following code snippet:
class Foo(val element: Option[Any], val element2: Any, ...)
val bar = new Foo(...)
val map = Map(bar.element match {
case None => ??? // Do not add an item here
case Some(el) => "element" -> el
}, "element2" -> element2, ...
)
The issue I have in this code snippet is with the None case. How do I specify that no element should be added here?
I have tried several things:
{}
here because it would be interpreted as a Unit
.case None =>
leads to a type mismatch; as it is also considered a Unit
while we need a Tuple2
.Map
definition, only adding an element in case of Some(el)
. However, this does not feel like a very elegant way to do this.case None =>
altogether, but this generates a warning, as the match is not exhaustive, and fails if the element is indeed None
.If I wanted to cover all the cases inside the Map definition, how can I indicate that in case of None
, no element should be added?
Some context: I'm using this as part of the (akka) spray json protocol definition for a certain type, and wondered if there is a shorthand way to do this without resorting to conditionally adding elements to a map.
Thanks in advance!
Based on the answer of mavarazy, I have solved this issue by code that looks something like this:
class Foo(val element: Option[Any], val element2: Any, ...)
val bar = new Foo(...)
val map = Map(bar.element match {
case None => "" -> null // Do not add an item here
case Some(el) => "element" -> el
}, "element2" -> element2, ...
).filter(_._2 != null)
Never thought of doing it that way, but I think it is still somewhat elegant. Thanks!
Upvotes: 1
Views: 1390
Reputation: 43
Using the 'collect' would be my preference since it takes a partial function i.e. only collects those values that match the patterns specified in the partial function -
val map: Map[String, Option[String]] = Map(
"element" -> Some("element"),
"element2" -> Some("element2"),
"element3" -> None
)
map collect { case (s, Some(e)) => (s, e) }
Upvotes: 0
Reputation: 7845
On option 3 you can remove the None case, by replacing .map by .collect which receives a partial function
Upvotes: 1
Reputation: 7735
There is nothing wrong with option 3 from my point of view, but If you don't like it, you can also do something like this:
val map = Map(
"element" -> element,
"element2" -> Option(element2)
).
filter(_._2.isDefined).
mapValues(_.get)
It will also prevent you from Map
with null
values in element2
, if this is one of your concerns.
Upvotes: 0