What is the right way to convert a variable of type java.util.HashMap<java.lang.String, java.util.List<java.lang.String>> in Java, to its Scala equivalent: Map[Map[String, List[String]]]? (with Scala Map, String and List)
I tried to use import scala.collection.JavaConverters._ and do JavaNestedMap.asScala but it failed. Is there a smart way of doing this (rather than having two maps)?
There's no single call way I know of.
This is succinct likely inefficient in a hot loop. Profile if it ends up being too slow and then you'd want to use builders directly.
val in: JMap[JMap[String, String]] = ???
val out: Map[Map[String, String]] = in.asScala.mapValues(_.asScala)
val again: JMap[JMap[String, String]] = out.map(_.asJava).asJava
It's worth noting that .asScala gives you a mutable map for consistency with the java map. If you want to get an immutable map back, you need to call .toMap afterwords.
Related
So far the only way I can figure is using:
var ans: TreeMap[Int, Int] = immutable.TreeMap(List(1,2,3).map(e => (e, e*2)): _*)
1) Is there a way to do it without using the vararg _* syntax?
2) Is this pattern a good practice in scala?
1) Is there a way to do it without using the vararg _* syntax?
Yes, you can use breakOut parameter to map. Note that this requires explicit type annotation on variable
import scala.collection.breakOut
import scala.collection.immutable.TreeMap
val ans: TreeMap[Int, Int] = List(1,2,3).map(e => (e, e*2))(breakOut)
2) Is this pattern a good practice in scala?
Until collections in Scala 2.13 allow you to write list.to(TreeMap), it's fine. I mean, it's not like there are better options, so use whatever solves your problem.
Is there a way to do it without using the vararg _* syntax?
Since the apply method on TreeMap takes vararg of type (A, B)*, I don't see any other built in way
Is this pattern a good practice in scala?
I don't see why it wouldn't be.
An alternative would be to provide an extension method in the form of toTreeMap map which could work.
1) The other way would be creating an empty TreeMap and then adding all elements:
immutable.TreeMap.empty[Int, Int] ++ (List(1,2,3).map(e => (e, e*2)))
I don't have strong feelings about which way is better.
2) Yes, this is fairly common.
I have two java maps which map a String to a set of Strings.
I want to convert the java maps to Scala and "add" map1 to map2 such that if they both have the same keys the value in the resultant map will be the union of the 2 value sets. I found a nice solution for the map addition:
map1 ++ map2.map { case (k,v) => k -> (v ++ map1.getOrElse(k,v))}
The issue happens when I convert the java maps to Scala via the 'asScala' call. When we do this conversation we get:
After the conversion to Scala, I am no longer able to run the solution above on these wrapper collections. The ++ operation on the map is still defined. However the SetWrapper class does not define a ++ operation. As far as I can tell the SetWrapper does not define any operations at all! Here is the full definition from the docs:
SetWrapper seems to extend an abstract class and does not define any of the functionality.
How can I get around this issue? Is there another conversation step to a real Set object?
JMapWrapper wraps a Java Map in a Scala Map; SetWrapper wraps a Scala Set in a Java Set. So it has Java's methods for Set, not Scala's.
You don't provide types, but it appears you start with a java.util.Map[SomeKey, java.util.Set[SomeType]]. Calling asScala on it will only convert the outer Map, not its values. You can fix this by using javaMap.asScala.mapValues(_.asScala) (with the usual caveat that it will call asScala each time a value is accessed; use .map instead if this isn't acceptable).
Scala newbie here,
I'm using stanford's topic modelling toolkit
and it has a lazy iterable of type LazyIterable[(String, Array[Double])]
How should i iterate through all the elements in this iterable say it to print all these values?
I tried doing this by
while(it.hasNext){
System.out.println(it.next())
}
Gives an error
error: value next is not a member of scalanlp.collection.LazyIterable[(String, Array[Double])]
This is the API source -> iterable_name ->
InferCVB0DocumentTopicDistributions in
http://nlp.stanford.edu/software/tmt/tmt-0.4/api/edu/stanford/nlp/tmt/stage/package.html
Based on its source code, I can see that the LazyIterable implements the standard Scala Iterable interface, which means you have access to all the standard higher-order functions that all Scala collections implement - such as map, flatMap, filter, etc.
The one you will be interested in for printing all the values is foreach. So try this (no need for the while-loop):
it.foreach(println)
Seems like method invocation problem, just check the source code of LazyIterable, look at line 46
override def iterator : Iterator[A]
when you get an instance of LazyIterable, invoke iterator method, then you can do what you want.
Following along with chapters and examples in "Scala for the Impatient", there's an exercise related to using a Java TreeMap as a Scala SortedMap. In the scala shell, I tried this:
var t: scala.collection.SortedMap[String,Int] = new java.util.TreeMap[String,Int]()
but I get an error message about type mismatch. Is there a simple way to do this?
Note: I did an import of scala.collection.JavaConversions._ and then did this:
var t: SortedMap[String,Int] = TreeMap[String,Int]()
This works, but variable t has type java.util.SortedMap, not scala.collection.SortedMap.
I haven't read that book, but you need to make your mind up. Is t a Scala SortedMap or is it a Java TreeMap?
A TreeMap isn't a SortedMap, so you can't assign one to a SortedMap variable without converting it. JavaConversions will do some conversions for you, including:
implicit def mapAsScalaMap [A, B] (m: Map[A, B]): Map[A, B]
Implicitly converts a Java Map to a Scala mutable Map.
However there's nothing to convert to a SortedMap.
If this conversion seems mysterious to you, the library designers would agree, so JavaConversions is deprecated in Scala 2.10, in favour of JavaConverters, which requires a specific .asScala method to do a conversion.
Unfortunately JavaConverters doesn't have anything to produce a SortedMap either (.asScala gives you a mutable.Map). So you need to rebuild the collection using its elements.
import collection.JavaConverters._
import collection.SortedMap
var t: SortedMap[String, Int] =
SortedMap[String, Int]() ++ new java.util.TreeMap[String,Int].asScala
Producing a new TreeMap in the code above is obviously a bit pointless because it's empty, but you should get the idea of how to deal with an existing one. If you don't have an existing one, just produce a new SortedMap in Scala.
import collection._
import JavaConverters._
var t: scala.collection.SortedMap[String,Int] =
new java.util.TreeMap[String,Int]().asScala.map(identity)(breakOut)
I'm trying to convert back from a parallel collection to a regular map. According to the api, if I call toMap on any appropriately defined parallel collection, it's supposed to return a standard Map, but it's returning ParMap over a flattened collection of iterables.
I have a
val task: Stream[Future[Iterable[Tuple2[String, String]]]]
And from which I get:
val res: ParSeq[Iterable[Tuple2[String, String]]] = tasks.par.map(f => f.apply())
Finally:
val finalresult = res.flatten.toMap
Unfortunately, the type of finalresult is ParMap[String, String].
On the other hand, if I call it like:
tasks.par.map(f => f.apply()).reduce(_++_).toMap
then the return type is Map[String, String].
Can someone tell me why this is? And (out of curiosity) how I can force convert a ParMap to a Map when scala won't let me?
As you go explicitly from sequential to parallel collection via .par, you go back to sequential via .seq. Since sets and maps have parallel implementations, toMap and toSet calls leave the collection in the current domain.
The example of reduce works because it, well, reduces the collection (the outer ParSeq disappears, leaving you with the inner (sequential) Iterable[Tuple2[...]]).