I have a simple map as below
val myMap = Map("A" -> "AB300","B" -> "XI134","C" -> null)
I would like to validate the length of a particular key and would like to return the value as string (and not as Option . I tried the following
myMap.getOrElse("A",null).toString.length
val res50: Int = 5
This works fine. But obviously, doesn't handle for null data
myMap.getOrElse("C",null).toString.length
//Null pointer Exception
Is there a way to handle null too? The expectation is length for a null value should return zero (may be replacing null with space or something)
You almost never need to use nulls in Scala, Option is great I don't see why you are insisting on not using it. Anyway, this is probably what you're looking for:
myMap.get("C")
.flatMap(Option.apply) // since some values are null in your map
.fold(ifEmpty = 0)(s => s.length)
Another solution:
util.Try(myMap("D").length).getOrElse(0)
Related
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
I was answering another question and tried to write this code:
val view = "0000000000".view
println(List(0,12,30,4).foldLeft(view)((s, i) => s.updated(i, '1')).mkString)
But this actually doesn't compile, and I had to convert it to seq and add an ugly type ascription for it to work.
I've noticed that "0000".view returns SeqView[Char, String] which is probably correct, but then when I do "000".view.updated(0, '1') it returns Seq[Char] = SeqViewP(...).
I'd expect it to return the same SeqView[Char, String]. Is this a bug, or am I missing something? What is the best way to fix it?
Is there a reason you need to convert the String to a view? Could you not just leave it as a String? This will be converted to a "string-like" SeqLike[Char] on an as-needed basis by an implicit conversion to StringOps, which ensures that the returned type for operations like .updated(...) will still be String Eg.:
println(List(0,12,7,4).foldLeft("000000000000000")((s, i) => s.updated(i, '1')).mkString)
// prints: 100010010000100
Note: I upped the length of the String, and changed one of the values in your list just to avoid issues with index values larger than the String's length, but how you prefer to deal with that problem is a different issue.
How does one represent null in scala for collections?
The equivalent for List's would be "Nil" and it would be represented as follows:
Nil.asInstanceOf[Map[String,String]]
What is the equivalent for Maps?
UPDATE The two working solutions that I am aware of, from experimenting as well as from the suggested solutions are "Map()" and "null.asInstanceOf(Map[String,String])". The Map() is not what I intended: i did not want an empty item but actually a non-existent one (aka null in java). I was already aware that Nil is only for Lists: it was intended to illustrate the flavor of entity I was searching for used by Map's. Using "null.asInstanceOf(..)" is not a scala-ish idiom. It appears there are no equivalents for Map ..?
The best way do to it is:
val x = Map.empty[String, String]
With a mutable map:
import scala.collection.mutable.{ Map => MMap }
val y = MMap.empty[String, String]
Nil is just an empty List. It is not related to null in any way.
Scala has null, just like Java, but it should almost always be avoided.
What is your actual goal?
Do you want an empty Map?
val m = Map[String,String]()
Or an empty mutable Map that can be added to?
val m = collection.mutable.Map[String,String]()
Or an Option[Map] that can be initialized later?
val m: Option[Map[String,String]] = None
Or actually a null?
var m: Map[String,String] = null
I've this code :
val total = ListMap[String,HashMap[Int,_]]
val hm1 = new HashMap[Int,String]
val hm2 = new HashMap[Int,Int]
...
//insert values in hm1 and in hm2
...
total += "key1" -> hm1
total += "key2" -> hm2
....
val get = HashMap[Int,String] = total.get("key1") match {
case a : HashMap[Int,String] => a
}
This work, but I would know if exists a better (more readable) way to do this.
Thanks to all !
It looks like you're trying to re-implement tuples as maps.
val total : ( Map[Int,String], Map[Int,Int]) = ...
def get : Map[Int,String] = total._1
(edit: oh, sorry, I get it now)
Here's the thing: the code above doesn't work. Type parameters are erased, so the match above will ALWAYS return true -- try it with key2, for example.
If you want to store multiple types on a Map and retrieve them latter, you'll need to use Manifest and specialized get and put methods. But this has already been answers on Stack Overflow, so I won't repeat myself here.
Your total map, containing maps with non uniform value types, would be best avoided. The question is, when you retrieve the map at "key1", and then cast it to a map of strings, why did you choose String?
The most trivial reason might be that key1 and so on are simply constants, that you know all of them when you write your code. In that case, you probably should have a val for each of your maps, and dispense with map of maps entirely.
It might be that the calls made by the client code have this knowledge. Say that the client does stringMap("key1"), or intMap("key2") or that one way or another, the call implies that some given type is expected. That the client is responsible for not mixing types and names. Again in that case, there is no reason for total. You would have a map of string maps, a map of int maps (provided that you are previous knowledge of a limited number of value types)
What is your reason to have total?
First of all: this is a non-answer (as I would not recommend the approach I discuss), but it was too long for a comment.
If you haven't got too many different keys in your ListMap, I would suggest trying Malvolio's answer.
Otherwise, due to type erasure, the other approaches based on pattern matching are practically equivalent to this (which works, but is very unsafe):
val get = total("key1").asInstanceOf[HashMap[Int, String]]
the reasons why this is unsafe (unless you like living dangerously) are:
total("key1") is not returning an Option (unlike total.get("key1")). If "key1" does not exist, it will throw a NoSuchElementException. I wasn't sure how you were planning to manage the "None" case anyway.
asInstanceOf will also happily cast total("key2") - which should be a HashMap[Int, Int], but is at this point a HashMap[Int, Any] - to a HashMap[Int, String]. You will have problem later on when you try to access the Int value (which now scala believes is a String)
Assume I have
var mp = Map[String,String]()
.....
val n = mp("kk")
The above will throw runtime error in case key "kk" did not exist.
I expected n will be null in case key did not exist. I want n to be null if key did not exist.
What is the proper way to handle this situation in scala with a short code sample?
First of all, you probably don't really want null, as that's almost always a sign of bad coding in Scala. What you want is for n to be of type Option[String], which says that the value is either a String or is missing. The right way to do that is with the .get() method on you map
val n = mp.get("kk")
If you really do need null (for interop with Java libraries, for example), you can use .getOrElse()
val n = mp.getOrElse("kk", null)
Try this:
val valueOpt = mp.get("kk")
Your result is of type Option[String] and can be either None or Some(actualValue). You can use pattern matching to find out:
valueOpt match {
case Some(value) => println(value)
case None => println("default")
}
A more appropriate way to do that kind of things, however, is to use the methods on Option, e.g.:
println(valueOpt.getOrElse("default"))
Look for the API docs for Option there.
Edit: Note that Mapitself directly defines a getOrElse method, too, as shown in Dave's answer.
val conversionRatios:mutable.Map[String, Double] = mutable.Map[String, Double](
"USD" -> 2.0,
"CNY" -> 3.0
)
val currentRate = conversionRatios.apply(key) // it will return you value or NoSuchElementException will be thrown