35

I am looking for an idiomatic solution to this problem.

I am building a val Scala (immutable) Map and would like to optionally add one or more items:

val aMap =
  Map(key1 -> value1,
      key2 -> value2,
      (if (condition) (key3 -> value3) else ???))

How can this be done without using a var? What should replace the ???? Is it better to use the + operator?

val aMap =
  Map(key1 -> value1,
      key2 -> value2) +
  (if (condition) (key3 -> value3) else ???))

One possible solution is:

val aMap =
  Map(key1 -> value1,
      key2 -> value2,
      (if (condition) (key3 -> value3) else (null, null))).filter {
        case (k, v) => k != null && v != null
      }

Is this the best way?

Ralph
  • 31,584
  • 38
  • 145
  • 282

3 Answers3

35

How about something along the lines of

val optional = if(condition) Seq((key3 -> value3)) else Nil
val entities = Seq(key1 -> value1, key2 -> value2) ++ optional
val aMap = entities.toMap
Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
sblundy
  • 60,628
  • 22
  • 121
  • 123
  • 3
    Nice! I can probably also do `Map(...) ++ (if(condition) Seq((key3 -> value3)) else Nil)` – Ralph May 18 '11 at 18:04
27

Another possibility is to take advantage of the iterable nature of Option.

A non-empty value o:

scala> val o = Some('z' -> 3)
scala> (Seq('x' -> 1, 'y' -> 2) ++ o).toMap
res1: scala.collection.immutable.Map[Char,Int] = Map(x -> 1, y -> 2, z -> 3)

An empty value o:

scala> val o = None
scala> (Seq('x' -> 1, 'y' -> 2) ++ o).toMap
res2: scala.collection.immutable.Map[Char,Int] = Map(x -> 1, y -> 2)
Eron Wright
  • 1,022
  • 12
  • 10
15

You can add directly to the map:

scala> val map = Map(1 -> 2, 3 -> 4)
scala> val some = Some(5 -> 6)
scala> val none = None
scala> val combinedMap = map ++ some ++ none
combinedMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4, 5 -> 6)
wwkudu
  • 2,778
  • 3
  • 28
  • 41
Mahmoud Hanafy
  • 1,861
  • 3
  • 24
  • 33
  • 1
    Nice. This is essentially using options iterable nature. Here ++ is an alias concat and you can concat any IterableOnce of Tuple2 to Map where types in Tuple2 match. – Ahe Nov 12 '19 at 12:16