Using array of maps in Jasper Reports/Scala - scala

I have the following Scala code that generates a Jasper Report using an array of maps as data source (JRMapArrayDataSource). This works fine if all the values have the same type (such as String), but when I try to combine strings and integers in the HashMap I get a compilation error:
val map1 = new HashMap[String,Object](Map("f1"->"aaa1", "f2"-> "aaa2", "f3" -> 1 ))
val map2 = new HashMap[String,Object](Map("f1"->"bbb1", "f2"-> "bbb2", "f3" -> 2 ))
val dataSource = new JRMapArrayDataSource(Array(map1, map2));
val params = new HashMap[String,Object]()
val jasperPrint = JasperFillManager.fillReport("test1.jasper", params, dataSource);
JasperExportManager.exportReportToPdfFile(jasperPrint, "test1.pdf");
In the line of map1 and map2 I get the following:
overloaded method constructor HashMap with alternatives: (x$1:
java.util.Map[_ <: String, _ <:
Object])java.util.HashMap[String,Object] (x$1:
Int)java.util.HashMap[String,Object] cannot be applied to
(scala.collection.immutable.Map[String,Any])
Since I have in the report two string fields (f1 and f2) and one int field (f3) I need to have this combination in the HashMap. Any ideas?

The answer is to use Any:
val map1 = new HashMap[String,Any](Map("f1"->"aaa1", "f2"-> "aaa2", "f3" -> 1 ))

Related

Java HashMap in Scala throws error

The following Scala code that uses java.util.HashMap (I need to use Java because it's for a Java interface) works fine:
val row1 = new HashMap[String,String](Map("code" -> "B1", "name" -> "Store1"))
val row2 = new HashMap[String,String](Map("code" -> "B2", "name" -> "Store 2"))
val map1 = Array[Object](row1,row2)
Now, I'm trying to dynamically create map1 :
val values: Seq[Seq[String]] = ....
val mapx = values.map {
row => new HashMap[String,String](Map(row.map( col => "someName" -> col))) <-- error
}
val map1 = Array[Object](mapx)
But I get the following compilation error:
type mismatch; found : Seq[(String, String)] required: (?, ?)
How to fix this?
We can simplify your code a bit more:
val mapx = Map(Seq("someKey" -> "someValue"))
This still produces the same error message, so the error wasn't actually related to your use of Java HashMaps, but trying to use a Seq as an argument to Scala's Map.
The problem is that Map is variadic and expects key-value-pairs as its arguments, not some data structure containing them. In Java a variadic method can also be called with an array instead, without any type of conversion. This isn't true in Scala. In Scala you need to use : _* to explicitly convert a sequence to a list of arguments when calling a variadic method. So this works:
val mapx = Map(mySequence : _*)
Alternatively, you can just use .to_map to create a Map from a sequence of tuples:
val mapx = mySequence.toMap

Scala : How to find types of values inside a scala nested collection

consider the following variables in scala :
val nestedCollection_1 = Array(
"key_1" -> Map("key_11" -> "value_11"),
"key_2" -> Map("key_22" -> "value_22"))
val nestedCollection_2 = Map(
"key_3"-> ["key_33","value_33"],
"key_4"-> ["key_44"->"value_44"])
Following are my questions :
1) I want to read the values of the variables nestedCollection_1, nestedCollection_2 and ensure that the value of the variables are of the format
Array[Map[String, Map[String, String]]
and
Map[String, Array[String]]]
2) Is it possible to get the detailed type of a variable in scala? i.e. nestedColelction_1.SOME_METHOD should return Array[Map[String, Map[String, String]] as type of its values
I am not sure what exacltly do you mean. Compiler can ensure type of any variable if you just annotate the type:
val nestedCollection_2: Map[String, List[String]] = Map(
"key_3"-> List("key_33", "value_33"),
"key_4"-> List("key_44", "value_44"))
You can see type of variable in scala repl when you define it, or using Alt + = in Intellij Idea.
scala> val nestedCollection_2 = Map(
| "key_3"-> List("key_33", "value_33"),
| "key_4"-> List("key_44", "value_44"))
nestedCollection_2: scala.collection.immutable.Map[String,List[String]] = Map(key_3 -> List(key_33, value_33), key_4 -> List(key_44, value_44))
Edit
I think I get your question now. Here is how you can get type as String:
import scala.reflect.runtime.universe._
def typeAsString[A: TypeTag](elem: A) = {
typeOf[A].toString
}
Test:
scala> typeAsString(nestedCollection_2)
res0: String = Map[String,scala.List[String]]
scala> typeAsString(nestedCollection_1)
res1: String = scala.Array[(String, scala.collection.immutable.Map[String,String])]

Scala :- Gatling :- Concatenation of two Maps stores last value only and ignores all other values

I have a two Maps and I want to concatenate them.
I tried almost all example given here Best way to merge two maps and sum the values of same key? but it ignores all values for key metrics and only stores last value.
I have downloaded scalaz-full_2.9.1-6.0.3.jar and imported it import scalaz._ but it won't works for me.
How can I concate this two maps with multiple values to same keys ?
Edit :-
Now I tried
val map = new HashMap[String, Set[String]] with MultiMap[String, String]
map.addBinding("""report_type""" , """performance""")
map.addBinding("""start_date""" ,start_date)
map.addBinding("""end_date""" , end_date)
map.addBinding("metrics" , "plays")
map.addBinding("metrics", "displays")
map.addBinding("metrics" , "video_starts")
map.addBinding("metrics" , "playthrough_25")
map.addBinding("metrics", "playthrough_50")
map.addBinding("metrics", "playthrough_75")
map.addBinding("metrics", "playthrough_100")
val map1 = new HashMap[String, Set[String]] with MultiMap[String, String]
map1.addBinding("""dimensions""" , """asset""")
map1.addBinding("""limit""" , """50""")
And tried to conver this mutable maps to immutable type using this link as
val asset_query_string = map ++ map1
val asset_query_string_map =(asset_query_string map { x=> (x._1,x._2.toSet) }).toMap[String, Set[String]]
But still I get
i_ui\config\config.scala:51: Cannot prove that (String, scala.collection.immutable.Set[String]) <:< (St
ring, scala.collection.mutable.Set[String]).
11:10:13.080 [ERROR] i.g.a.ZincCompiler$ - val asset_query_string_map =(asset_query_string map { x=> (x
._1,x._2.toSet) }).toMap[String, Set[String]]
Your problem is not related with a concatenation but with a declaration of the metrics map. It's not possible to have multiple values for a single key in a Map. Perhaps you should look at this collection:
http://www.scala-lang.org/api/2.10.3/index.html#scala.collection.mutable.MultiMap
You can't have duplicate keys in a Map.
for simple map it is impossible to have duplicates keys,if you have the duplicates keys in the map it takes the last one
but you can use MultiMap
import collection.mutable.{ HashMap, MultiMap, Set }
val mm = new HashMap[String, Set[String]] with MultiMap[String, String]
mm.addBinding("metrics","plays")
mm.addBinding("metrics","displays")
mm.addBinding("metrics","players")
println(mm,"multimap")//(Map(metrics -> Set(players, plays, displays)),multimap)
I was able to create two MultiMaps but when I tried to concatenate val final_map = map1 ++ map2
and I tried answer given here Mutable MultiMap to immutable Map
But my problem was not solved, I got
config\config.scala:51: Cannot prove that (String, scala.collection.immutable.Set[String]) <:< (St
ring, scala.collection.mutable.Set[String]).
finally it solved by
val final_map = map1 ++ map2
val asset_query_string_map = final_map.map(kv => (kv._1,kv._2.toSet)).toMap

Nested Map withDefaultValue changes default value

I have a mutable map containing another mutable map, both with default values. After I assign a value to one key in the enclosed map, its default value seems to change.
I.e. I expected anotherDefault to have the value Map(1 -> default), NOT Map(1 -> something).
Why is this happening?
scala> import scala.collection.mutable.{Map => MMap}
import scala.collection.mutable.{Map=>MMap}
scala> val amap = Map[Int, MMap[Int, String]]().withDefaultValue(MMap().withDefaultValue("default"))
amap: scala.collection.immutable.Map[Int,scala.collection.mutable.Map[Int,String]] = Map()
scala> val bmap = amap(2)
bmap: scala.collection.mutable.Map[Int,String] = Map()
scala> bmap(1)
res17: String = default
scala> bmap(1) = "something"
scala> val anotherDefault = amap(3)
anotherDefault: scala.collection.mutable.Map[Int,String] = Map(1 -> something)
The outer map (amap) is creating a single instance of the inner map to use as the default. When you access this via val bmap = amap(2), then modify bmap, you are modifying the single default map used by amap. When you call amap(3), you then get back this default map, which is now a map with the key/value pair (1 -> "something").
What you probably want is withDefault, not withDefaultValue, although it needs some extra argument/type specification to work:
val amap = Map[Int, MMap[Int, String]]().withDefault(x => MMap[Int, String]().withDefaultValue("default"))

Creating nested Map with different type

I am try to create map with different map inside
val mymap = Map("name"->"somename",Map(1->2))
I got from compiler:
scala: type mismatch;
found : scala.collection.immutable.Map[Int,Int]
required: (?, ?)
val mymap = Map("name"->"somename",Map(1->2))
^
Why do you expect it to work? You've provided only key without value:
val key = Map(1->2)
val mymap = Map("name"->"somename", key)
Perhaps you wanted to combine two maps? This can be done with:
val mymap = Map("name"->"somename") ++ Map(1->2)
// scala.collection.immutable.Map[Any,Any] = Map(name -> somename, 1 -> 2)
A Map consists of key-value pairs (whose type is (?, ?)). You have to assign the Map value to a key as well:
val mymap = Map("name"->"somename","othername"->Map(1->2))