How to save the output of the match statement into variable? - scala

I have an piece of code where i have used the pattern matching inside it i have used map in all cases, i want to get the output of what map is giving to a variable. Below is my code:
override def run():List[Option[Student]] =
StudentDataCache.get(surname) match {
case Some(i) => i.otherSiblings.map(siblings =>
StudentDataCache.get(siblings) match {
case Some(i) => Some(i)
case None=> getStudentFromDatabase(siblings)
}
)
case None =>
getStudentFromDatabase(surname).get.otherSiblings.map(siblings => StudentDataCache.get(siblings) match {
case Some(i) => Some(i)
case None=> getStudentFromDatabase(siblings)
}
)
}
output of both the map statement inside case is List[Option[Student]], is there a way to get this into variable because i want to convert this list into a single object since HystrixCommand execute output does not supports List as output. I want to convert it to StudentListing(val listing: List[Option[Student]])

just... assign it to a value / variable:
override def run(): StudentListing = {
val result = StudentDataCache.get(surname) match { /* same code*/ }
StudentListing(result) // or however you wrap it into a StudentListing...
}
A match expression, like any other expression in Scala, is evaluated into a value - you can do whatever you want with this value.

Related

scala: updating string value in an option

I have an Option of a string. I want to update the contained value:
if(x.isEmpty) {
...another calculation
} else {
x.map(val => ...update val)
}
Is this an idiomatic way?
x.fold(another calculation)(v => ...update v)
e.g.
x.fold("no value")("Value is " + _)
Note that this extracts the value from the Option so if you want to have the result as an Option you need to wrap it in Some.
Note that if your inner computation gets too long or unreadable for a fold, there's always good old-fashioned pattern matching.
x match {
case None => {
// None case ...
}
case Some(y) => {
// Some case (y is the inside) ...
}
}
Like everything in Scala, this is an expression, so it can be assigned to a variable or used in another other expression you like.
Alternatively, using the lazy keyword:
// T is the type of the value
val valueOpt: Option[T] = ???
lazy val backupValue: T = ??? // Other calculation, but only evaluated if needed
val value: T = valueOpt.map( v => /*Update v*/ ).getOrElse( backupValue )
// do something with the value you want to manipulate

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

Scala methods with generic parameter type

I have been working with Scala for close to a year, but every now and then I come across a piece of code that I don't really understand. This time it is this one. I tried looking into documents on "scala methods with generic parameter type", but I am still confused.
def defaultCall[T](featureName : String) (block : => Option[T])(implicit name: String, list:Seq[String]) : Option[T] =
{
val value = block match {
case Some(n) => n match {
case i : Integer => /*-------Call another method----*/
case s : String => /*--------Call another method----*/
}
case _ => None
}
The method is called using the code shown below :
var exValue = Some(10)
val intialization = defaultCall[Integer]("StringName"){exValue}
What I don't understand in the above described code is the "case" statement in the defaultCall method.
I see that when the exValue has a value and is not empty, the code works as expected. But in case I change the exValue to None, then my code goes into the "case _ = None" condition. I don't understand why this happens since the match done here is against the "variable" which would be either an Integer or a String.
What happens here is that when you pass a None it will match on the second case, which "catches" everything that is not an instance of a Some[T]:
block match {
case Some(n) => // Will match when you pass an instance of Some[T]
case _ => // Will match on any other case
}
Note that None and Some are two different classes that inherit from Option.
Also, the variable match is only done if the first match succeeds, otherwise not. To achieve the type checking in the first match you could do:
block match {
case Some(n: Int) => // do stuff
case Some(n: String) => // do stuff
case _ => // Will match on any other case
}
Hope that helps

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

Pattern matching a domain name

I don't use pattern matching as often as I should.
I am matching a domain name for the following:
1. If it starts with www., then remove that portion and return.
www.stackoverflow.com => "stackoverflow.com"
2. If it has either example.com or example.org, strip that out and return.
blog.example.com => "blog"
3. return request.domain
hello.world.com => "hello.world.com"
def filterDomain(request: RequestHeader): String = {
request.domain match {
case //?? case #1 => ?
case //?? case #2 => ?
case _ => request.domain
}
}
How do I reference the value (request.domain) inside the expression and see if it starts with "www." like:
if request.domain.startsWith("www.") request.domain.substring(4)
You can give the variable you pattern matching a name and Scala will infer its type, plus you can put an if statement in you case expression as follows
def filterDomain(request: RequestHeader): String = {
request.domain match {
case domain if domain.startsWith("www.") => domain.drop(4)
case domain if domain.contains("example.org") | domain.contains("example.com") => domain.takeWhile(_!='.')
case _ => request.domain
}
}
Note that the order of the case expressions matters.
When writing case clauses you can do something like:
case someVar if someVar.length < 2 => someVar.toLowerCase
This should make pretty clear how grabbing matched values works.
So in this case, you would need to write something like:
case d if d.startsWith("www.") => d.substring(4)
If you're dead set on using a regex rather than String methods such as startsWith and contains, you can do the following:
val wwwMatch = "(?:www\\.)(.*)".r
val exampleMatch = "(.*)(?:\\.example\\.(?:(?:com)|(?:org)))(.*)".r
def filterDomain(request: String): String = {
request.domain match {
case wwwMatch(d) => d
case exampleMatch(d1, d2) => d1 + d2
case _ => request.domain
}
}
Now, for maintainability's sake, I wouldn't go this way, because a month later, I will look at this and not remember what it's doing, but that's your call.
you don't need pattern matching for that:
request.domain
.stripPrefix("www.")
.stripSuffix(".example.org")
.stripSuffix(".example.com")