Scala case match a String - scala

I'm trying to match case against a String and have the following code:
val selectedAnswers: List[Int] = questionType match {
case "CHECK_BOX" => {
answerCheckBox match {
case Some(answers) => answers
case None => List()
}
}
case "RADIO_BUTTON" => {
answerRadio match {
case Some(answer) => List(answer)
case None => List()
}
}
case _ => {
List()
}
}
Why is it not falling through the _ case when the String is not RADIO_BUTTON or CHECK_BOX?
The values for answerRadio and answerCheckbox are actually coming from the form that I'm submitting to the controller.
val (currentQuesId, questionType, answerRadio, answerCheckBox) = runExamForm.bindFromRequest.get
And the form declaration looks like:
val runExamForm = Form(
tuple(
"currentQuestionId" -> number,
"questionType" -> text,
"answerRadio" -> optional(number),
"answerCheckbox" -> optional(list(number))
)
)

This is "equivalent" version of your code:
val selectedAnswers: List[Int] = questionType match {
case "CHECK_BOX" => answerCheckBox.toList.flatten
case "RADIO_BUTTON" => answerRadio.toList
case _ => List()
}
Does it work as expected?

It's a long shot, but try replacing the _ with some other name (x is fine) and make sure that your code contains nothing but regular whitespace.
Very rarely I've seen bizarre errors like this caused by other non-printing characters in the code, which always seemed to be caused by pasting code from a chat on the OSX Skype client.
Also... Can you confirm in your code sample which line the MatchError occurs on?

Related

Validation JSON schema runtime

I want to avoid Runtime undefined behaivors as follows:
val jsonExample = Json.toJson(0)
jsonExample.asOpt[Instant]
yield Some(1970-01-01T00:00:00Z)
How can I verify this using partial function with a lift or some other way, to check thatits indeed Instant, or how you recommend to validate?
ex1:
val jsonExample = Json.toJson(Instant.now())
jsonExample match { ... }
ex2:
val jsonExample = Json.toJson(0)
jsonExample match { ... }
Examples for desired output:
validateInstant(Json.toJson(Instant.now())) -> return Some(...)
validateInstant(Json.toJson(0)) -> return None
I can do somthing as follows, maybe some other ideas?
Just wanted to add a note regarding parsing json, there some runtime undefined problems when we are trying to parse .asOpt[T]
for example:
Json.toJson("0").asOpt[BigDecimal] // yields Some(0)
Json.toJson(0).asOpt[Instant] // yields Some(1970-01-01T00:00:00Z)
We can validate it as follows or some other way:
Json.toJson("0") match {
case JsString(value) => Some(value)
case _ => None
}
Json.toJson(0) match {
case JsNumber(value) => Some(value)
case _ => None
}
Json.toJson(Instant.now()) match {
case o # JsString(_) => o.asOpt[Instant]
case _ => None
}
You can use Option:
def filterNumbers[T](value: T)(implicit tjs: Writes[T]): Option[Instant] = {
Option(Json.toJson(value)).filter(_.asOpt[JsNumber].isEmpty).flatMap(_.asOpt[Instant])
}
Then the following:
println(filterNumbers(Instant.now()))
println(filterNumbers(0))
will output:
Some(2021-02-22T10:35:13.777Z)
None

Retrieve tuple from string

I have the following input string:
"0.3215,Some(0.5123)"
I would like to retrieve the tuple (0.3215,Some(0.5123)) with: (BigDecimal,Option[BigDecimal]).
Here is one of the thing I tried so far:
"\\d+\\.\\d+,Some\\(\\d+\\.\\d+".r findFirstIn iData match {
case None => Map[BigDecimal, Option[BigDecimal]]()
case Some(s) => {
val oO = s.split(",Some\\(")
BigDecimal.valueOf(oO(0).toDouble) -> Option[BigDecimal](BigDecimal.valueOf(lSTmp2(1).toDouble))
}
}
Using a Map and transforming it into a tuple.
When I try directly the tuple I get an Equals or an Object.
Must miss something here...
Your code has several issues, but the big one seems to be that the case None side of the match returns a Map but the Some(s) side returns a Tuple2. Map and Tuple2 unify to their lowest-common-supertype, Equals, which is what you're seeing.
I think this is what you're trying to achieve?
val Pattern = "(\\d+\\.\\d+),Some\\((\\d+\\.\\d+)\\)".r
val s = "0.3215,Some(0.5123)"
s match {
case Pattern(a,b) => Map(BigDecimal(a) -> Some(BigDecimal(b)))
case _ => Map[BigDecimal, Option[BigDecimal]]()
}
// Map[BigDecimal,Option[BigDecimal]] = Map(0.3215 -> Some(0.5123))

Scala match case on regex directly

I am trying to do something like the following:
list.foreach {x =>
x match {
case """TEST: .*""" => println( "TEST" )
case """OXF.*""" => println("XXX")
case _ => println("NO MATCHING")
}
}
The idea is to use it like groovy switch case regex match. But I can't seem to get to to compile. Whats the right way to do it in scala?
You could either match on a precompiled regular expression (as in the first case below), or add an if
clause. Note that you typically don't want to recompile the same regular expression on each case evaluation, but rather have it on an object.
val list = List("Not a match", "TEST: yes", "OXFORD")
val testRegex = """TEST: .*""".r
list.foreach { x =>
x match {
case testRegex() => println( "TEST" )
case s if s.matches("""OXF.*""") => println("XXX")
case _ => println("NO MATCHING")
}
}
See more information here and some background here.
Starting Scala 2.13, it's possible to directly pattern match a String by unapplying a string interpolator:
// val examples = List("Not a match", "TEST: yes", "OXFORD")
examples.map {
case s"TEST: $x" => x
case s"OXF$x" => x
case _ => ""
}
// List[String] = List("", "yes", "ORD")

How to use a Map value in a match case statement in Scala

I have a map like this:
val mealIdsMap: Map[String, String] =
Map (
"breakfast" -> "omelet",
"lunch" -> "steak",
"dinner" -> "salad"
)
Then I try to use it in a match statement like this:
"omelet" match
{
case mealIdsMap("breakfast") => "Thank God"
}
And I get this error:
error: value mealIdsMap is not a case class constructor,
nor does it have an unapply/unapplySeq method
case mealIdsMap("breakfast") => "Thank God"
Anyone know how to use a map like this in a match/case statement?
Thanks alot for your help.
You should read what is the purpose of pattern matching from a tutorial, may be from this one (first non trivial example on google).
You have inverted the test:
mealIdsMap("breakfast") match {
case "omelet" => "Thank God"
case _ => "Don't forget a default"
}
And if you're not sure that the key is present (and even if you are, if you want to write idiomatic scala, you should prefer:
mealIdsMap.get("breakfast") match {
case Some("omelet") => "Thank God"
case _ => "Don't forget a default"
}
Where getreturns an option, avoiding you to try catch your code or to let it break silently.
Though, its still interesting to try to achieve such a behavior. have a look at this example:
case class InvMatcher (m:Map[String, String]){
def unapply(v:String):Option[String] = {
return m collectFirst {case (k, `v`) => k}
}
}
This class helps you to inverse-match a map.
usage:
val ma = InvMatcher (Map (
"breakfast" -> "omelet",
"lunch" -> "steak",
"dinner" -> "salad"
));
"steak" match {
case ma(s) => s match {
case "breakfast" => print("Thank God")
case "lunch" => print("whatever")
case _ => print("dont forget default")
}
case _ => print("dont forget default")
}
This is nearly as you wanted it though you need a second match-statement (which doesnt need a default case here...)

How to match a string on a prefix and get the rest?

I can write the code like this:
str match {
case s if s.startsWith("!!!") => s.stripPrefix("!!!")
case _ =>
}
But I want to know is there any better solutions. For example:
str match {
case "!!!" + rest => rest
case _ =>
}
val r = """^!!!(.*)""".r
val r(suffix) = "!!!rest of string"
So suffix will be populated with rest of string, or a scala.MatchError gets thrown.
A different variant would be:
val r = """^(!!!){0,1}(.*)""".r
val r(prefix,suffix) = ...
And prefix will either match the !!! or be null. e.g.
(prefix, suffix) match {
case(null, s) => "No prefix"
case _ => "Prefix"
}
The above is a little more complex than you might need, but it's worth looking at the power of Scala's regexp integration.
Starting Scala 2.13, it's now possible to pattern match a String by unapplying a string interpolator:
"!!!hello" match {
case s"!!!$rest" => rest
case _ => "oups"
}
// "hello"
If it's the sort of thing you do often, it's probably worth creating an extractor
object BangBangBangString{
def unapply(str:String):Option[String]= {
str match {
case s if s.startsWith("!!!") => Some(s.stripPrefix("!!!"))
case _ => None
}
}
}
Then you can use the extractor as follows
str match{
case BangBangBangString(rest) => println(rest)
case _ => println("Doesn't start with !!!")
}
or even
for(BangBangBangString(rest)<-myStringList){
println("rest")
}
Good question !
Even i was trying a lot to find out the answer.
Here is a good link where I found the answer
object _04MatchExpression_PatternGuards {
def main(args: Array[String]): Unit = {
val url: String = "Jan";
val monthType = url match {
case url if url.endsWith(".org") => "Educational Websites";
case url if url.endsWith(".com") => "Commercial Websites";
case url if url.endsWith(".co.in") => "Indian Websites"
case _ => "Unknow Input";
}
}
}