scala.collection.immutable.$colon$colon cannot be cast to java.lang.String - scala

I am iterating with a map with key-value as
Map(fields -> List(
pangaea_customer_id, email_hash, savings_catcher_balance,
is_savings_catcher_member, billing_zipcode
))
I am trying below code to get the value of fields key
val fields = ValuesMap.get("fields")
But I am not able to convert fields to comma-separated String.
Please help me on how to do this.
I am trying with
val fields = ValuesMap.get("fields").mkString(",")
but it will return
List(pangaea_customer_id, email_hash, savings_catcher_balance,
is_savings_catcher_member, billing_zipcode)

get returns an Option[V] (because the key may be unmapped, and then it needs to return None).
Option can be iterated, just like a List, so you can call mkString on it, but it only ever returns at most one element, so the separator character will not be used.
Try getOrElse("fields", Seq.empty).mkString(",")
What your version did is:
get("fields") returns Some(List(....))
you call mkString on the Option, will will just give you either an empty String (if it was None), or (in your case), the result of toString for the element inside (which is the List as a whole).

You can try this:
val fields = res8.get("fields").getOrElse(List()).mkString(",")
// output: fields: String = pangaea_customer_id,email_hash,savings_catcher_balance,is_savings_catcher_member,billing_zipcode

Related

How do I retrieve a value from a JSON string using gatling JsonPath.query?

Given a string:
val json = """{"id":"derp"}"""
When I try to retrieve the value of ID using JsonPath I get the empty iterator
import io.gatling.jsonpath.JsonPath
JsonPath.query("$.id", json).right.get
// Iterator[Any] = empty iterator
How do I get the value of id?
Although the type of the second arg to JsonPath.query is Any, this function does not seem to support multiple types of arguments. It does not parse the input string, but expects it already to be parsed. Looks a bit weird as design choice.
So, supposing that Jackson is used as the parser lib, the following will work and select the value under id key:
val json = """{"id":"derp"}"""
val parsed = new ObjectMapper().readValue(json, classOf[Object])
// to retrieve the ids as a list:
val ids = JsonPath.query("$.id", parsed).right.get.toList
// the only "id" result of the query
val id = ids.head

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: mutable HashMap does not update inside for loop

I have a var permutedTables = HashMap[List[Int], List[String, String]] defined globally. I first populate the Hashmap with the keys in a method, which works.
print(permutedTables) :
Map(List(1,2,3,4) -> List(),
List(2,4,5,6) -> List(), etc...)
The problem occurs when I want to update the values (empty lists) of the HashMap inside a for loop (inside a second method). In other words, I want to add tuples (String, String) in the List() for each key.
for(pi_k <- permutedTables.keySet){
var mask = emptyMask;
mask = pi_k.foldLeft(mask)((s, i) => s.updated(i, '1'))
val maskB = Integer.parseInt(mask,2)
val permutedFP = (intFP & maskB).toBinaryString
// attempt 1 :
// permutedTables(pi_k) :+ (url, permutedFP)
// attempt 2 :
// permutedTables.update(pi_k, permutedTables(pi_k):::List((url, permutedFP)))
}
The values do not update. I still have empty lists as values. I don't understand what is wrong with my code.
EDIT 1: When I call print(permutedTables) after any of the two attempts (inside the loop), the value seem updated, but when I call it outside of the loop, the Lists are empty
EDIT 2: The second attempt in my code seems to work now(!). But why does first not work ?
The second attempt in my code seems to work now(!). But why does first not work ?
Because what you do in the first case is get a list from permutedTables, add an element and throw away the result without storing it back. It would work if you mutated the value, but a List is immutable. With List, you need
permutedTables += pi_k -> permutedTables(pi_k) :+ (url, permutedFP)
Or, as you saw, update.
You can use e.g. ArrayBuffer or ListBuffer as your value type instead (note that you need :+= instead of :+ to mutate them), and convert to your desired type at the end. This is going to be rather more efficient than appending to the end of the list, unless the lists are quite small!
Finally, note that you generally want either var or a mutable type, not both at the same time.

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

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]]

How to create a collection of unique values based on existing array values

Below code prints an Array of fileNames.
val pdfFileArray = getFiles()
for(fileName <- pdfFileArray){
println(fileName)
}
I'm trying to convert this Array (pdfFileArray) into an array which contains unique file name extensions.
Is something like below the correct way of doing this in scala ?
Set<String> fileNameSet = new HashSet<String>
val pdfFileArray = getFiles()
for(fileName <- pdfFileArray){
String extension = fileName.substring(fileName.lastIndexOf('.'));
fileNameSet.add(extension)
}
This will properly handle files with no extension (by ignoring them)
val extensions = getFiles().map{_.split('.').tail.lastOption}.flatten.distinct
so
Array("foo.jpg", "bar.jpg", "baz.png", "foobar")
becomes
Array("jpg", "png")
You could do this:
val fileNameSet = pdfFileArray.groupBy(_.split('.').last).keys
This assumes that all you filenames will have an extension and you only want the last extension. i.e. something.html.erb has the extension 'erb'
There's a method in scala's collection called distinct, which takes away all duplicate entries in the collection. So for instance:
scala> List(1, 2, 3, 1, 2).distinct
res3: List[Int] = List(1, 2, 3)
Is that what you're looking for?
For a sake of completeness:
List("foo.jpg", "bar.jpg").map(_.takeRight(3)).toSet
Here I'm assuming that all extensions are 3 chars long. Conversion to Set, just like .distinct method (which uses mutable set underneath, by the way) in other answers gives you unique items.
You can also do it with regex, which gives a more general solution because you can redefine the expression to match anything you want:
val R = """.*\.(.+)""".r
getFiles.collect{ case R(x) => x }.distinct