monkeyshrines
monkeyshrines

Reputation: 25

Scala: Conditionally add element in a Map definition based on pattern match

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:

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!

Edit: suggested solution

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

Answers (3)

Meghana Viswanath
Meghana Viswanath

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

pedrorijo91
pedrorijo91

Reputation: 7845

On option 3 you can remove the None case, by replacing .map by .collect which receives a partial function

Upvotes: 1

mavarazy
mavarazy

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

Related Questions