Scala compiler says: value & is not a member of java.lang.object - scala

I am very new to Scala, I try some tutorials but I didn't get the point in this problem here:
val reverse = new mutable.HashMap[String, String]() with mutable.SynchronizedMap[String, String]
def search(query: String) = Future.value {
val tokens = query.split(" ")
val hits = tokens map { token => reverse.getOrElse(token, Set()) }
if (hits.isEmpty)
Nil
else
hits reduceLeft {_ & _} toList // value & is not a member of java.lang.Object
}
The compiler says value & is not a member of java.lang.Object. Can somebody explain me why I am getting a compiler error ? I have this from this tutorial here: https://twitter.github.io/scala_school/searchbird.html

"tokens" is of type Array[String]. Now, when you iterate over the array, there are two possibilities. Either reverse will have a value for the token or not. If it has, then the Array element get a string value otherwise an empty set.
For example: Lets say reverse has two values - ("a" -> "a1", "b" ->"b1") a maps to a1 and b maps to b1.
Suppose, The query string is "a c".
tokens will be ["a","c"] after splitting.
After mapping you will get in array ["a1", Set()] (a got mapped to a1 and there is no value for "c" in the map hence, you got an empty Set())
Now, the overall type of the hits array is Array[Object].
So, now you are getting an error as the last line will be "&" operator on 2 Objects according to the compiler.

Mohit Has The right answer, you end up with an Array of objects. This is because your HashMap for reverse has a value type of String, so it'll return a String for a given key. Your getOrElse however, will return a Set type if the key is not found in your HashMap reverse. These need to return the same type so you don't end up with an Array[Objects]
If you notice a few lines above in the tutorial you linked, reverse is defined as follows:
val reverse = new mutable.HashMap[String, Set[String]] with mutable.SynchronizedMap[String, Set[String]]

Related

Compile time error in scala Map while I put an object inside value

I am having one Map containing two Scala objects as value and unique string.
val vv = Map("N"-> Nconstant, "M"-> Mconstant)
Here the Nconstant and Mconstant are two Objects having constant values in it. After that, I try to access the constant variable inside that object by passing the key below,
val contract = vv("N").contractVal
contractVal is the variable which has values and is inside both the Mconstant and Nconstant.
But IntelliJ is showing
"Cannot resolve symbol contractVal".
Can anyone help with this issue?
As an addition to Tim's answer, in case you've got types that have a common field but don't have a common type, then you can use duck typing:
object Nconstant {
val contractVal = "N"
}
object Mconstant {
val contractVal = "M"
}
val vv = Map("N"-> Nconstant, "M"-> Mconstant, "X" -> Xconstant)
import scala.language.reflectiveCalls
vv("N").asInstanceOf[{ val contractVal: String }].contractVal //N
But beware, it will fail on runtime if N doesn't really have contractVal field!
It sounds like Nconstant and Mconstant are different types that happen to have the same field contractVal. If so, you need to determine which type you have by using match:
val contract = vv("N") match {
case n: Nconstant => n.contractVal
case m: Mconstant => m.contractVal
}
This will throw a MatchError if the value is neither Nconstant or Mconstant.

Cast Exception When trying to cast a Coordinate Matrix

Hi I am very new to Scala and Spark. I am writing a test to check the integrity of my data. For this I have a Coordinated Matrix and I map it with the ResultMap. Now in my Testing method I need to fetch it from result map and covert the type into Coordinate it raised an Exception in thread
"main" java.lang.ClassCastException: scala.Some cannot be cast to org.apache.spark.mllib.linalg.distributed.CoordinateMatrix
This is my code .
def SinghTest(map:Map[String,Any ]):Boolean={
var res:Boolean=false // false
val connection= DriverManager.getConnection("Connectionstring ")
val statement = connection.createStatement();
val rs = statement.executeQuery("select A,B from Demo P" +
" join Demo_REL R on p.id=R.ID " +
"join Cpu CN on CN.id=R.CID" +
" limit 10 ");
/***
* Maping with ResultMap
***/
val matrix=map.get("MatrixEntries").asInstanceOf[CoordinateMatrix]
matrix.entries.take(10).foreach(x=> {
val ph=x.i
val ch=x.j
val pid=rs.getLong(1)
val cid=rs.getLong(2)
if((ph!=pid)&&ch!=cid)
throw new Exception("Fail")
})
The get method on maps does not return the element directly, but an Option of it. This means, for a Map[String, Any] the result type is Option[Any]. An option can either contain a value or be empty; if your maps contains the key, you will get a Some with the value, otherwise a None. You can then operate on the value using the methods on Option or get it via getOrElse, which takes a default value to use if it was a None.
val matrix = map.getOrElse("MatrixEntries", someDefaultMatrix).asInstanceOf[CoordinateMatrix]
If you are sure that the map contains the key, you can access the elements directly by using map(key), just leaving out the .get. This will give you the element directly, but throw an exception, if the key is not defined for your map.
val matrix = map("MatrixEntries").asInstanceOf[CoordinateMatrix]
PS: Note that using Any is usually considered bad style, as it throws away any type safety. If your map contains a mostly fixed set of keys and you have control over its creation (i.e. it's not from a library), look into replacing it with a case class:
case class TestData(matrixEntries: CoordinateMatrix /* further elements here */)
// ...
val matrix = testData.matrixEntries // no casting required, type errors checked at compile time
I did it this way, using the help of #crater2150
val matrix=map("MatrixEntries").asInstanceOf[CoordinateMatrix] // But the conversion is required.

scala hashmap get string value returns some()

val vJsonLoc = new HashMap[String, String]();
def getPrevJson(s:String) = vJsonLoc.get(s)
val previousFile = getPrevJson(s"/${site.toLowerCase}/$languagePath/$channel/v$v/$segment")
this returns
Some(/Users/abc/git/abc-c2c/)
on trying to append string previousFile + "/" + index + ".json"
the result is Some(/Users/abc/git/abc-c2c/)/0.json when the desired result is /Users/abc/git/abc-c2c/0.json
Guess this is some concept of Option that have not understood. New to scala.
As you pointed out, you're getting back an Option type, and not a direct reference to the String contained in your data structure. This is a very standard Scala practice, allowing you to better handle cases where an expected value might not be present in your data structure.
For example, in Java, this type of method typically returns the value if it exists and null if it doesn't. This means, however, subsequent code could be operating on the null value and thus you'd need further protection against exceptions.
In Scala, you're getting a reference to an object which may, or may not, have the value you expect. This is the Option type, and can be either Some (in which case the reference is accessible) or None (in which case you have several options for handling it).
Consider your code:
val vJsonLoc = new HashMap[String, String]();
def getPrevJson(s:String) = vJsonLoc.get(s)
val previousFile = getPrevJson(s"/${site.toLowerCase}/$languagePath/$channel/v$v/$segment")
If the HashMap returned String, your previousFile reference could point to either a null value or to a String value. You'd need to protect against a potential exception (regular practice in Java).
But in Scala, get is returning an Option type, which can be handled in a number of ways:
val previousFile = getPrevJson("your_string").getOrElse("")
//or
val previousFile = getPrevJson("your_string") match {
case Some(ref) => ref
case None => ""
}
The resulting reference previousFile will point to a String value: either the expected value ("get") or the empty string ("OrElse").
Scala Map on get returns Option. Use vJsonLoc(s) instead of vJsonLoc.get(s)

scala accessing a list object inside another list

I am trying to access a list object inside of another list with a specific type
val x = List ("item1" , "item2" , List ("a","b","c"))
val list_from_x :List [String]= x(2) // producing error
I need my list_from_x of type to be of List [String]
any idea how to I do such conversion ?
So x is of type List[Object]**, because you've used two different (otherwise unrelated) classes as elements of that list.
You'll be unable to access elements other than of type Any without a type cast:
val listFromX = x(2).asInstanceOf[List[String]]
This is not type-safe, so you'll want to check element types (x(2).isInstanceOf[List[_]]) or pattern matching.
** Use the REPL to verify this; though val x: List[Any] = List ("item1" , "item2" , List ("a,b,c")) works
HList to the rescue:
import shapeless._
import Nat._
val x = "item1" :: "item2" :: List("a,b,c") :: HNil
val list_from_x = x(_2)
list_from_x has the type List[String]
See the shapeless github page for more info.
As other answers have mentioned, a List can only hold elements of a certain type. For example, a List[String] can only hold Strings. If you put elements of mixed types into a List, then the parametrised type of the List will become the most specific type common to all the elements.
The most specific type common to String and List is Any. So in this example, x is of type List[Any]:
val x = List("item1" , "item2" , List ("a,b,c"))
HList can hold elements of different types and maintain each element's type.
Scala compiler will simply say you got Objects (or may be Any) inside list x. That's why. You have to cast the 3rd element into a List in order to assign into a List variable.
The issue is List is defined as List[+A] (source). Which means List takes a type parameter of co-variant type. (You can think of co-variance as type converting from narrow to broader. For ex: if Dog extends Animal and if you do Animal a = new Dog(), you have a Dog (narrow) converting to Animal (broader))
x is of type List[Object]. Doing
scala> val x = List ("item1" , "item2" , List ("a,b,c"))
x: List[Object] = List(item1, item2, List(a,b,c))
val list_from_x :List [String]= x(2)
is ultimately converting from List[Object] (broader) to List[String] (narrow). Which is contra-variant. Hence the compiler threw error because List is meant to be co-variant.
For ex: the below is completely valid. Thanks to co-variance:
scala> val x = List("hello")
x: List[String] = List(sdf)
scala> val o:List[Object] = x
o: List[Object] = List(sdf)
More about it here and here

Type alias for immutable collections

What is the best way to resolve the compilation error in the example below? Assume that 'm' must be of type GenMap and I do not have control over the arguments of myFun.
import scala.collection.GenMap
object Test {
def myFun(m: Map[Int, String]) = m
val m: GenMap[Int, String] = Map(1 -> "One", 2 -> "two")
//Build error here on m.seq
// Found scala.collection.Map[Int, String]
// Required scala.collection.immutable.Map[Int, String]
val result = myFun(m.seq)
}
EDIT:
I should have been clearer. In my actual use-case I don't have control over myFun, so I have to pass it a Map. The 'm' also arises from another scala component as a GenMap. I need to convert one to another, but there appears to be a conflict between collection.Map and collection.immutable.Map
m.seq.toMap will solve your problem.
According to the signature presented in the API toMap returns a scala.collection.immutable.Map which is said to be required in your error message. scala.collection.Map returned by the seq method is a more general trait which besides being a parent to immutable map is also a parent to the mutable and concurrent map.