I recently stumbled over this post, which "introduces" the collect
method for Scala collections. The usage is straight forward:
scala> val ints = List(1, "2", 3) collect { case i: Int => i }
ints: List[Int] = List(1, 3)
Now maps are basically lists of key-value pairs, which are represented by tuples in Scala. So you might wanna try something like this:
scala> val pairs = Map(1 -> "I", "II" -> 2)
pairs: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2)
scala> val intsToStrings = pairs collect { case pair: (Int, String) => pair }
The compiler complains of course due to the type erasure model of the JVM, so the first thing we try is using existential types:
scala> val intsToStrings = pairs collect { case pair: (_, _) => pair }
intsToString: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2)
Although the code passed the compiler, and the result is "correct" (we wanted pairs => we got pairs) we still didn't get what we actually wanted. The second attempt looks like this:
scala> val intsToStrings = pairs collect {
| case pair: (_, _) if pair._1.isInstanceOf[Int] && pair._2.isInstanceOf[String] => pair
| }
intsToStrings: scala.collection.immutable.Map[Any,Any] = Map(1 -> I)
Ok, we are almost there:
scala> val realIntsToRealStrings = intsToStrings map {
| pair => (pair._1.asInstanceOf[Int], pair._2.asInstanceOf[String])
| }
realIntsToRealStrings: scala.collection.immutable.Map[Int,String] = Map(1 -> I)
We did it, but instead of only casting from (Any,Any)
to (Int,String)
we actually copied each pair and thus created a new pair.
Now comes the question part. As I mentioned "The compiler complains of course..." I made it sound like I really know what I'm talking about. I don't! All I know is that Java didn't have generics from the beginning. At some point generics came into Java but not into the JVM. So the compiler checks all the types, but as soon as the code is running, JVM does not care for the parametric type. It only sees that it's a Map
or a List
but not that it's a Map[String, Int]
or List[Int]
.
So here is my question.
With all the checking, casting and mapping, we managed to transfer a Map[Any,Any]
to Map[String,Int]
. Is there a better way of doing that? I mean the types are there, JVM just does not see them (as far as I am concerned)...
Scala Map get() method with example The get() method is utilized to give the value associated with the keys of the map. The values are returned here as an Option i.e, either in form of Some or None. Return Type: It returns the keys corresponding to the values given in the method as argument.
The collect function is applicable to both Scala's Mutable and Immutable collection data structures. The collect method takes a Partial Function as its parameter and applies it to all the elements in the collection to create a new collection which satisfies the Partial Function.
We can insert new key-value pairs in a mutable map using += operator followed by new pairs to be added or updated.
pairs collect { case p @ (_: Int, _: String) => p.asInstanceOf[(Int, String)] }
or more concise, but with some overhead, I think
pairs collect { case (x: Int, y: String) => (x, y) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With