Reputation: 5031
I have a map of Map[String, Info], it contains keys which can be either uppercase or lowercase, like this:
person1: PersonInfo1
person2: PersonInfo2
PERSON1: PersonInfo1
i want to get the value for key 'person1', if nothing found I'll try with key of 'PERSON1', I tried this code:
val info = map.get(key) match {
case Some(personInfo) => personInfo
case None =>
map.get(key.toUpperCase()) match {
case Some(personInfo) => personInfo
case None => None
}
}
but this return info as type of Product with Serializable, how can I have info returned as type of PersonInfo? Is there a way in Scala that allow me to get value from map by key and ignore cases of the key?
Upvotes: 5
Views: 3909
Reputation: 113
You can do a find
instead of a get
but you may want to consider performance when doing this.
map.find(k => k._1.equalsIgnoreCase(key)) match {
case Some =>
case None =>
}
Upvotes: 4
Reputation: 22595
You could chain gets with orElse
. I would create an extension method for that:
implicit class CaseInsensitiveGetMap[V] (m: Map[String,V]) {
def iget (key: String): Option[V] = m.get(key)
.orElse(m.get(key.toUpperCase())) //you can add more orElse in chain
}
Then you can just use it like:
map.iget("person2")
Upvotes: 7
Reputation: 51271
The reason you're getting Product with Serializable
is because your code is trying to return either a String
(if key is good) or an Option
(i.e. None
if key not found). Those two types are not compatible. You should decide if you want String
(maybe an empty string if key not found) or Option
(i.e. Some[String]
or None
).
See if this works for you. It returns an Option[String]
.
map.get(key).fold(pm.get(key.toUpperCase))(Some(_))
The 1st get()
returns an Option
. The fold()()
unwraps the Option
and either tries a 2nd get()
with upper case key
value, or, if the 1st get
returned a value, the value is re-wrapped in an Option
so that the types match up.
If, on the other hand, you want to return a String
instead, you might do this.
map.getOrElse(key, pm.getOrElse(key.toUpperCase, ""))
Upvotes: 4
Reputation: 9100
There are comparators for sorted maps which allow getting from the map case insensitively. Example: https://scastie.scala-lang.org/PfHTh16CROag7PNrknx1sQ
val map = scala.collection.immutable.SortedMap("key1" -> 45, "Key2" -> 43, "KEY3" -> 42)(scala.math.Ordering.comparatorToOrdering(String.CASE_INSENSITIVE_ORDER))
map.get("key1") // Some(45)
map.get("key2") // Some(43)
map.get("key3") // Some(42)
map.get("key4") // None
Your actual problem can be fixed if you return Options on all cases, for example:
val info = map.get(key) match {
case somePi@Some(personInfo) => somePi
case None => map.get(key.toUpperCase()) match {
case Some(personInfo) => Some(personInfo)
case None => None
}
}
Note the somePi@
=> somePi
parts for referring the expression or the Some(personInfo)
.
Probably worth explaining why you got this error message. I assume personInfo
is a case class
which implements Product
and Serializable
, just like None
. The common type for them is Product with Serializable
.
Upvotes: 8