Is a more idiomatic (and hopefully elegant) way to make Scala an immutable map of variable elements (lengths)?

I need to make elements along these lines

val aMap = Map("A" -> 1)
val bMap = if (b > -1) { aMap ++ Map("B" -> b) } else aMap
val cMap = if (!c.equals("")) { bMap ++ Map("C" -> c) } else bMap

Yes, it should (and does) return Map[String, Any]by design - unsure, I can get more specific information about Any, and since the data is cleared and converted to strings later, this is not a problem (at least for the purposes of this question)

Of course, I would like to make one card in one shot. Keep in mind that this is a simple case - in other cases of use there may be many elements.

I try not to break and use mutable, except as a last resort :)

+4
source share
5 answers

, Map, . - :

implicit class MapExt[A, B](m: Map[A, B]) {
    def withValueIf(condition: => Boolean)(kv: (A, Any)): Map[A, Any] =
        if(condition) m + kv else m
}

:

 val b = -2
 val c = "abc"

 Map("A" -> 1)
     .withValueIf(b > -1)("B" -> b)
     .withValueIf(c.nonEmpty)("C" -> c)

 res28: Map[String,Any] = Map(A -> 1, C -> abc)

-, kv: (A, Any) kv: Map[A, Any] m + kv m ++ kv. , if(condition) m + kv else m .

- , Any, :

implicit class MapExt[A, B](m: Map[A, B]) {
    def withValueIf[C <: B](condition: => Boolean)(kv: (A, C)): Map[A, B] =
        if(condition) m + kv else m
}

scala> Map("a" -> 1).withValueIf(b < 0)("B" -> b).withValueIf(c.nonEmpty)("C" -> -1)
res30: Map[String,Int] = Map(a -> 1, B -> -2, C -> -1)

implicits, if/else , .

def cMap[A, B](condition: => Boolean)(m: Map[A, B]): Map[A, B] =
    if(condition) m else Map.empty

 Map("A" -> 1) ++
     cMap(b > -1)(Map("B" -> b)) ++
     cMap(c.nonEmpty)(Map("C" -> c))
+4

, ( ) ( ) . (, F #) |>. Scala , :

implicit class piped[A](private val a: A) extends AnyVal {
  def |>[B](f: A => B): B = f(a)
}

:

val theMap = Map("A" -> 1) |> 
 (m => if(b > -1) m ++ Map("B" -> b) else m) |>
 (m => if(c != "") m ++ Map("C" -> c) else m)

val theMap = Map("A" -> 1) |> 
 (if(b > -1) (_ ++ Map("B" -> b)) else identity) |>
 (if(c != "") (_ ++ Map("C" -> c)) else identity)

.

+1

- :

Map("A" -> 1) ++ 
  (if (b > -1) Map("B" -> b) else Map.empty)  ++
  (if (c != "") Map("C" -> c) else Map.empty) ++  
  // etc...
+1

+ (String, Any) ++ :

Map("A" -> 1) + ("B" -> 2)

Map, (String, Any):

Map("A" -> 1, "B" -> 2)

, , :

val mySequenceOfTuples = Seq("A" -> 1, "B" -> "foo")
Map(mySequenceOfTuples:_*)
//Or, equivalently
mySequenceOfTuples.toMap

, 1 :

Seq(
    Some("A" -> 1), 
    Some("B" -> b).filter(_._2 > -1),  
    Some("C" -> c).filterNot(_.isEmpty)
).flatten.toMap 

Another approach is to build a complete map and then filter:

Map("A" -> 1, "B" -> b, "C" -> c).filter { 
    case ("B", b) => b > -1 
    case ("C", c) => !c.isEmpty 
    //Keep all others in the default case
    case _ => true 
}

Finally, you can also use ++along with the fact that merging an empty card is no-op:

Map("A" -> b) ++ 
    (if(b > -1) Map("B" -> b) else Map.empty) ++ 
    (if(!c.isEmpty) Map("C" -> c) else Map.empty) 
0
source

I would do something like

val aMap = Map("A" -> 1)
def bMap(b: Int) = if (b > -1) Some("B" -> b) else None
def cMap(c: String) = if (c.nonEmpty) Some("C" -> c) else None

Then:

scala> aMap ++ bMap(1) ++ cMap("")
res1: scala.collection.immutable.Map[String,Any] = Map(A -> 1, B -> 1)
0
source

All Articles