Scala equivalent of new HashSet(Collection) - java

What is the equivalent Scala constructor (to create an immutable HashSet) to the Java
new HashSet<T>(c)
where c is of type Collection<? extends T>?.
All I can find in the HashSet Object is apply.

The most concise way to do this is probably to use the ++ operator:
import scala.collection.immutable.HashSet
val list = List(1,2,3)
val set = HashSet() ++ list

There are two parts to the answer. The first part is that Scala variable argument methods that take a T* are a sugaring over methods taking Seq[T]. You tell Scala to treat a Seq[T] as a list of arguments instead of a single argument using "seq : _*".
The second part is converting a Collection[T] to a Seq[T]. There's no general built in way to do in Scala's standard libraries just yet, but one very easy (if not necessarily efficient) way to do it is by calling toArray. Here's a complete example.
scala> val lst : java.util.Collection[String] = new java.util.ArrayList
lst: java.util.Collection[String] = []
scala> lst add "hello"
res0: Boolean = true
scala> lst add "world"
res1: Boolean = true
scala> Set(lst.toArray : _*)
res2: scala.collection.immutable.Set[java.lang.Object] = Set(hello, world)
Note the scala.Predef.Set and scala.collection.immutable.HashSet are synonyms.

From Scala 2.13 use the companion object
import scala.collection.immutable.HashSet
val list = List(1,2,3)
val set = HashSet.from(list)

Related

How to create a Hashmap in Scala with key as String and value as another String or another Hashmap

I want to create a variable in Scala which can have data of the following format:
"one" -> "two",
"three -> {"four" -> "five", "six -> "seven"},
"eight" -> {"nine" -> { "ten" -> "eleven", "twelve" -> "thirteen"},
"fourteen" -> {"fifteen" -> "sixteen}
}
I tried creating a Java HashMap using:
var requiredVar = new HashMap[String, Object]()
I am able to do something like :
var hm = new HashMap[String, String]
hm.put("four","five")
requiredVar.put("three",hm)
But if I try to add :
requiredVar.get("three").put("six","seven")
I get the error that
value put is not a member of Object
How can I get this done?
I have tried something like native to Scala as well:
val a = Map("one" -> "two" , "three" -> Map("four"->"five"))
a.get("three").put("six"->"seven")
but get the following error:
error: value put is not a member of Option[Any]
In the first case, when using Java, you get the error because the compiler doesn't know that the value that retrieved from requiredVar is a Map.
You declare requiredVar to be a HashMap[String, Object], so the compiler will only know anything retrieved from the map is an Object, nothing more specific.
Specifically, in your case:
requiredVar.get("three").put("six","seven")
requiredVar.get("three") returns an Object, which doesn't have a put() method.
You are running into a similar issue in the Scala version of your code as well. When you create the Map:
val a = Map("one" -> "two" , "three" -> Map("four"->"five"))
the compiler must infer the types of the keys and values, which it is doing by finding the closest common ancestor of all the values, which for a String and another Map, is Any, Scala's equivalent to Java's Object. So when you try to do
a.get("three").put("six"->"seven")
a.get("three") is returning an Option[Any], which doesn't have a put method. By the way, Scala's Map.get returns an Option, so that if the key is not present in the map, a None is returned instead an exception being thrown. You can also use the more concise method a("three"), which returns the value type directly (in this case Any), but will throw an exception if the key is not in the map.
There are a few ways I can think of try to achieve what you want to do.
1) Casting
If you are absolutely sure that the value you are retrieving from the map is another Map instead of a String, you can cast the value:
requiredVar.get("three").asInstanceOf[HashMap[String, String]].put("six","seven")
This is a fairly brittle approach, as if the value is a String, then you will get a runtime exception thrown.
2) Pattern Matching
Rather than casting arbitrarily, you can test the retrieved value for its type, and only call put on values you know are maps:
requiredVar.get("three") match {
case m: HashMap[String, String] => m.put("six", "seven")
case _ => // the value is probably a string here, handle this how you'd like
}
This allows you to guard against the case that the value is not a map. However, it is still brittle because the value type is Any, so in the case _ case, you don't actually know the value is a String, and would have to pattern match or cast to know for sure and use the value as a String
3) Create a new value type
Rather than rely on a top type like Object or Any, you can create types of your own to use as the value type. Something like the following could work:
import scala.collection.mutable.Map
sealed trait MyVal
case class StringVal(s: String) extends MyVal
case class MapVal(m: Map[String, String]) extends MyVal
object MyVal {
def apply(s: String): StringVal = StringVal(s)
def apply(m: Map[String, String]): MapVal = MapVal(m)
}
var rv = Map[String, MyVal]()
rv += "one" -> MyVal("two")
rv += "three" -> MyVal(Map[String, String]("four" -> "five"))
rv.get("three") match {
case Some(v) => v match {
case MapVal(m) => m("six") = "seven"
case StringVal(s) => // handle the string case as you'd like
}
case None => // handle the key not being present in the map here
}
The usage may look similar, but the advantage now is that the pattern match on the rv.get("three") is complete.
4) Union types
If you happen to be using a 3.x version of Scala, you can use a union type to specify exactly what types of values you will have in your map, and achieve something like the above option much less verbosely:
import scala.collection.mutable.Map
val rv: Map[String, String | Map[String, String]] = Map()
rv += "one" -> "two"
rv += "three" -> Map[String, String]("four" -> "five")
rv.get("three") match {
case Some(m: Map[String, String]) => m += "six" -> "seven"
case Some(s: String) => // handle string values
case None => // handle key not present
}
One thing to note though, with all of the above options, is that in Scala, it is preferable to use immutable collections, instead of mutable versions like HashMap or scala.collection.mutable.Map (which is by default a HashMap under the hood). I would do some research about immutable collections and try to think about how you can redesign your code accordingly.

How to covert a Java collection into a Kotlin Sequence (and vice versa) in Java?

I am implementing a Kotlin interface in Java which expects me to return a Sequence<T>.
How can I convert a Java collection into a Kotlin Sequence? Conversely, how can I convert a Kotlin Sequence into a Java collection?
Here are some conversions:
val javaList = java.util.ArrayList<String>()
javaList.addAll(listOf("A", "B", "C"))
// From Java List to Sequence
val seq = sequenceOf(*javaList.toTypedArray())
// or
val seq2 = javaList.asSequence()
// Sequence to Kotlin List
val list = seq.toList()
// Kotlin List to Sequence
val seqFromList = sequenceOf(*list.toTypedArray())
// or
val seqFromList2 = list.asSequence()
// Sequence to Java List
val newJavaList = java.util.ArrayList<String>().apply { seqFromList.toCollection(this) }
// or
val newJavaList2 = java.util.ArrayList<String>()
newJavaList2.addAll(seqFromList)
Since the Kotlin code gets run from Java, it gets a bit trickier.
Let's try to recreate the scenario:
Kotlin:
interface SequenceInterface {
fun foo(list: List<Int>) : Sequence<Int>
}
If you inspect Kotlin code, you will discover that there's no particular implementation of the Sequence interface. So, in your case, you need to implement it by yourself (just like Kotlin is doing when calling asSequence:
public class Foo implements SequenceInterface {
#NotNull
public Sequence<Integer> foo(final List<Integer> list) {
return () -> list.listIterator();
}
}
and then you can start using it in Java:
new Foo().foo(Arrays.asList(42))
Keep in mind that all useful methods will be gone since they are implemented as Kotlin extensions.
Want to convert to List? In plain Java, just reiterate:
ArrayList<Integer> list = new ArrayList<>();
seq.iterator().forEachRemaining(list::add);
Also, make sure that you absolutely need to return a Sequence in Kotlin's code. If you want to achieve better interoperability, returning a Stream would make more sense.
Like this:
val javaList = java.util.ArrayList<String>()
val kotlinSeq = javaList.asSequence()
val newJavaList = java.util.ArrayList<String>().apply { kotlinSeq.toCollection(this) }

convert scala hashmap with List to java hashmap with java list

I am new to scala and spark.I have below case class A
case class A(uniqueId : String,
attributes: HashMap[String, List[String]])
Now I have a dataFrame of type A. I need to call a java function on each row of that DF. I need to convert Hashmap to Java HashMap and List to java list..
How can i do that.
I am trying to do following
val rddCaseClass = RDD[A]
val a = rddCaseClass.toDF().map ( x=> {
val rowData = x.getAs[java.util.HashMap[String,java.util.List[String]]]("attributes")
callJavaMethod(rowData)
But this is giving me error :
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to java.util.List
Please help.
You can convert Scala Wrapped array to Java List using
scala.collection.JavaConversions
val wrappedArray: WrappedArray[String] = WrappedArray.make(Array("Java", "Scala"))
val javaList = JavaConversions.mutableSeqAsJavaList(wrappedArray)
JavaConversions.asJavaList can also be used but its deprecated: use mutableSeqAsJavaList instead
I think, you could use Seq instead of List for your parameters to work efficiently with List. This way it should work with most of the Seq implementations and no need to to convert the seqs like WrappedArray.
val rddCaseClass = RDD[A]
val a = rddCaseClass.toDF().map ( x=> {
val rowData = x.getAs[java.util.HashMap[String, Seq[String]]]("attributes")
callJavaMethod(rowData)

Update of the element in the DenseVector class, Spark

how is it possible to update some element with the index i in the object of the class DenseVector?
Is it possible? Well, it is:
scala> val vec = Vectors.dense(1, 2, 3)
vec: org.apache.spark.mllib.linalg.Vector = [1.0,2.0,3.0]
scala> vec.toArray(0) = 3.0
scala> vec
res28: org.apache.spark.mllib.linalg.Vector = [3.0,2.0,3.0]
I doubt it is an intended behavior though. Since Vectors don't implement update method there are clearly designed as immutable data structures.

accessing java two-dimensional vector from scala

Here's my case:
I created a table with DefaultTableModel
So when I use getDataVector I get a two-dimensional java.util.Vector.
When I use toSeq or any other converter I get something like
Buffer([5.0, 1.0, 50.0], [10.0, 1.5, 40.0], [2.0, 1.5, 90.0], [1.0, 1.0, 100.0], [6.0, 3.0, 100.0], [16.0, 3.5, 50.0])
The inner objects are returned as java.lang.Object (AnyRef in scala), and not as arrays
How can I convert them or access their contents?
Here is the code to test
import collection.mutable.{Buffer, ArrayBuffer}
import javax.swing.table._
import scala.collection.JavaConversions._
var data = Array(
Array("5.0", "1.0", "50.0"),
Array("10.0", "1.5", "40.0"),
Array("2.0", "1.5", "90.0"),
Array("1.0", "1.0", "100.0"),
Array("6.0", "3.0", "100.0"),
Array("16.0", "3.5", "50.0"))
val names = Array("K¹", "K²", "K³")
val m = new DefaultTableModel(data.asInstanceOf[Array[Array[AnyRef]]], names.asInstanceOf[Array[AnyRef]])
val t = m.getDataVector.toSeq
This is an older interface in Java, so it returns a pre-generic Vector (i.e. a Vector[_]). There are a variety of ways you could deal with this, but one is:
val jv = m.getDataVector.asInstanceOf[java.util.Vector[java.util.Vector[AnyRef]]]
val sv = jv.map(_.toSeq)
to first explicitly specify what the return type ought to be, and then convert it into Scala collections. If you prefer to convert to immutable collections, you can
val sv = Vector() ++ jv.map(Vector() ++ _)
among other things. (These are now Scala immutable vectors, not java.util.Vectors.)
If you want to mutate the vectors that were returned, just use jv as-is, and rely upon the implicit conversions to do the work for you.
Edit: added a couple other ways to get immutable collections (possible, but I wouldn't say that they're better):
val sv = List(jv.map(v => List(v: _*)): _*)
val sv = Vector.tabulate(jv.length,jv(0).length)((i,j) => jv(i)(j))
Note that the second only works if the table is nonempty and rectangular.

Categories