How to write map from string to function with arguments in Scala - scala

I am working on a project where i supposed to work with conversion based on the key. Since there are lot of key are there I was supposed to write a case for each key and logic for that code. But this approach leads to increase in lines of code.
So I was required to change the code by using
map(key ->fun(length ,description, convertionMatchCase)
val h = scala.collection.mutable.Map(
"01" -> tagfunction(2, "Tag Length", "ToInt"),
"02" -> tagfunction(1, "Firmware version", "ToInt"),
"03" -> tagfunction(15, "IMEI", "ToASCII"),
"04" -> tagfunction(2, "Device ID", "ToInt"),
"10" -> tagfunction(2, "No of Archive records", "ToInt"),
"20" -> tagfunction(4, "Date and time", "ToInt"),
//"30" -> tagfunction(9, "Coordinates", "ToASCII"),
//"33" -> tagfunction(4, "Speed and direction", "ToASCII"),
"34" -> tagfunction(2, "Height", "ToSignedShort"),
"35" -> tagfunction(1, "HDOP", "ToInt"),
"40" -> tagfunction(2, "Status of device", "ToInt"),
"41" -> tagfunction(2, "Supply Voltage", "ToInt"),
"42" -> tagfunction(2, "Battery Voltage", "ToInt"),
"43" -> tagfunction(1, "Temperature of tracking device", "ToSignedByte"),
)
The problem is that function's inside the map are executing automatically(even when i'm using lazy after calling a single map(key) every thing was executing)
Could any one please suggest me some solution. Thanks you

First of all try to avoid using mutable Map's in favor of immutable ones as it is a more idiomatic approach in Scala.
Secondly - your Map is not a map from key to function, it is a map from key to a value. Possibly you are looking for lambda expressions:
val h = Map(
"01" -> (() => tagfunction(2, "Tag Length", "ToInt")),
"02" -> (() => tagfunction(1, "Firmware version", "ToInt")),
...
)
This will allow to get invokable function by key, though it is not very clear why do you need to invoke it every time (cause usually having functions with side effects is also considered non-idiomatic approach for Scala, at least by some =).

I am not sure why number of lines matters in the first place ... but here is how you can minimize it:
val map = Map( // do not use mutable!
"foo" -> (1, "bar"),
"baz" -> (2, "bat"),
"bam" -> (3, "baz")
)
def convert(key: String) = tagfunction.tupled(map(key))
The last line might need a bit of an explanation. tagfunction.tupled converts a function of two arguments Int, String into a function with a single argument, which is a tuple (Int, String). Because tuples are stored in the map, you get one with map(key), and can send it directly into the function.
A longer way to write it would be:
val (n,s) = map(key)
tagfunction(n,s)
But since you are after minimizing the number of lines, I thought, I'd show you that little trick.

Related

How to filter List of Maps in Scala

My list of Maps is like below
val myMap= List(
Map("name" -> "1st" , "status" -> "0"),
Map("name" -> "2nd" , "status" -> "1"),
Map("name" -> "3rd" , "status" -> "1")
)
I am trying to filter the list based on "status" = "1" and get another List of Maps with only name
So the output should be
Map("name" -> "2nd"),
Map("name" -> "3rd")
I am a beginner in scala, understand that I need to apply map,filter. But not getting how to proceed here.
If you are doing both filter and map the best solution is often to use collect:
myMap.collect{ case m if m.get("status").contains("1") => m - "status" }
Consider combining filter & map into collect:
val myMap = List(
Map("name" -> "1st", "status" -> "0"),
Map("name" -> "2nd", "status" -> "1"),
Map("name" -> "3rd", "status" -> "1"),
Map("xx" -> "4th", "status" -> "1"),
Map("name" -> "5th", "yy" -> "1")
)
myMap.collect{ case m if m.get("status").contains("1") && m.get("name").nonEmpty =>
Map("name" -> m("name"))
}
// List(Map(name -> 2nd), Map(name -> 3rd))
The guard clause in collect ensures that only those Maps consisting of key-value status->1 as well as key name will be included.
With filter and map you can write is as follows
myMap
.filter(m => m.get("status") == Some("1")) // filter maps with status 1
.map(m => "name" -> m.get("name").get) // use the name attribute to create a new map
Note that the get method returns an Option since the requested key might not exist. Therefore you need to compare with Some("1") and also use the .get on the result of m.get("name"). Using the .get method without checking that the option is not empty is not a good style, since this will fail at runtime if the map doesn't contain a name key.
A better approach which would omit these maps from the result could be
myMap
.filter(m => m.get("status") == Some("1"))
.flatMap(m => m.get("name").map(n => "name" -> n))
The map used here is from the Option class and will map a found name to Some("name" -> n) and None to None. The flatMap will finally unpack the Some and ignore the None elments

Better way to create new key in map if key doesnt exist in Scala?

I have the following list of maps in Scala:
val list = List(Map( "age" -> 25, "city" -> "London", "last_name" -> "Smith"),
Map("city" -> "Berlin", "last_name" -> "Robinson"))
And I wish to iterate through the list of maps and check if the key "age" exists. If it doesnt, I want to create the entry and put it in the map. So far I have tried:
val tmp = list.map( item => if (!item.contains("age")) item.updated("age",5) else item)
print(tmp)
which works fine, I just wanted to know if there is a more efficient way to do it (perhaps with comprehensions or anything else?)! Any advice would be appriciated
I'd do it this way.
val newList =
list.map{m => if (m.keySet("age")) m else m + ("age" -> "5")}
Note that if you don't make the value 5 a String then the result is a Map[String,Any], which is not what you want.

correct use of scala Map keyset

I am fussing about how to derive a key from a Scala Map.
The Map in question is simple:
The following function to derive a key from a Scala Map is here under:
def extractKey(myMap: Map[String, String]): String {
//process myMap
myMap = Map("SSN" -> "1")
//return "SSN"
}
val myMap = Map("Visa Number" "10")
How do I extract the string Visa Number from it?
Okay, I tried this much so far:
myMap.keySet and I derived a Set out of it as: scala.collection.immutable.Set[String] = Set("Visa Number")
I am a little confused about to proceed.
I tried the following:
myMap.keys
this returned a Iterable[String] = Set("Visa Number")
I also tried the following:
myMap.keysIterator that returned an Iterator[String]
So, what is the best way to derive a key out of the Map myMap
Now, what if I had a longer Map as:
myMapLonger = Map("SSN" -> "10", "AMEX" -> 11)
then how would i capture the keys and put them into a List?
thanks
Map("SSN" -> "10", "AMEX" -> 11).keys.toSeq
or
Map("SSN" -> "10", "AMEX" -> 11).toSeq.map(_._1)
One approach invloves applying unzip on the given Map,
val (keys,values) = Map("SSN" -> "10", "AMEX" -> 11).unzip
which delivers a duple of lists, the first entry with the keys, the second with the values
keys: List(SSN, AMEX)
values: List(10, 11))

Scala map extract value repeated maximum times

I have Map[String,String]so keys are distinct but most values are repeated.
For example : Map[car-> "This is a car",truck-> "This is a car", fruit ->"This is a fruit"]
So it should return "This is a car" because it is repeated twice.
I did something like this. Hope it helps.
val j = x.groupBy(_._2)
Then
j.maxBy(_._2.size)
Where x is your original map. The first call, returns a Map and then you just get the key value pair where the value (map , has max entries)
val m1 = Map("this" -> "that", "what" -> "that", "who" -> "me", "you" -> "who")
m1.groupBy(_._2).maxBy(_._2.size)
res0: ... = (that,Map(this -> that, what -> that))
Another solution
map.values.groupBy(t => t ).values.maxBy(_.size).head
Not the most elegant but my solution goes like
val list = Map(car-> "This is a car",truck-> "This is a car", fruit ->"This is a fruit")
list.map{
case (k,v) => if(list.filter{case (key,value)=> value==v }.size>1)v
}.toSet

Play 2.0 form - field "verifying" method is not a member

Practicing what is written here: ScalaForms, I have created the following form:
val personCreationForm = Form(
tuple (
"name" -> nonEmptyText,
"age" -> number verifying (min(0), max(100)) /*ERROR*/
) verifying ("Wrong entry", result => result match {
case (name, age) => true
})
)
However, the error on verifying states that value verifying is not a member of (java.lang.String, play.api.data.Mapping[Int]).
Working with mapping instead of tuple, as in the referenced example, makes no difference. What is wrong here?
According to Scala operators precedence rules, methods starting with a letter have a lower precedence than others so when you write:
"age" -> number verifying (min(0), max(100))
The compiler builds the following expression:
("age" -> number) verifying (min(0), max(100))
Which is not what you want! You can rewrite it as follows:
"age" -> number.verifying(min(0), max(100))
"age" -> (number verifying (min(0), max(100)))
And the current Play documentation is wrong. Thanks for catching it!