In the following code the first expression returns a Result[String] which contains one of the strings "medical", "dental" or "pharmacy" inside of a Result. I can add .toOption.get to the end of the val statement to get the String, but is there a better way to use the Result? Without the .toOption.get, the code will not compile.
val service = element("h2").containingAnywhere("claim details").fullText()
service match {
case "medical" => extractMedicalClaim
case "dental" => extractDentalClaim
case "pharmacy" => extractPharmacyClaim
}
Hard to say without knowing what Result is. If it's a case class, with the target String as part of its constructor, then you could pattern match directly.
Something like this.
service match {
case Result("medical") => extractMedicalClaim
case Result("dental") => extractDentalClaim
case Result("pharmacy") => extractPharmacyClaim
case _ => // default result
}
If the Result class doesn't have an extractor (the upapply() method) you might be able to add one just for this purpose.
I'm assuming this Result[T] class has a toOption method which returns an Option[T] - if that's the case, you can call toOption and match on that option:
val service = element("h2").containingAnywhere("claim details").fullText().toOption
service match {
case Some("medical") => extractMedicalClaim
case Some("dental") => extractDentalClaim
case Some("pharmacy") => extractPharmacyClaim
case None => // handle the case where the result was empty
}
Related
I have a pattern matching for sealed trait which expects two of one case classes as shown below:
expressions.head match {
case SingleValueExpression(value,_operator,_ignoreCase) => filter ++ FromScala(
SingleValueExpression(value,_operator,_ignoreCase)
).transform(ToJson.string)
case MultipleValueExpression(value,_operator,_apply,_instances) => filter ++ FromScala(
MultipleValueExpression(value,_operator,_apply,_instances)
).transform(ToJson.string)
}
You can see that even after decoding the case classes, I am recreating the case class in the next step:
case MultipleValueExpression(value,_operator,_apply,_instances) => MultipleValueExpression(value,_operator,_apply,_instances)
Is there a way to match the pattern such that I could check if the instance is of that case class and then use the value as it is instead of destructuring it and recreating the same case class?
To just check the type in a pattern match, use :, like so:
expressions.head match {
case sve: SingleValueExpression => filter ++ FromScala(sve).transform(ToJson.string)
case mve: MultipleValueExpression => filter ++ FromScala(mve).transform(ToJson.string)
}
You could even have something like
val fromScala =
expressions.head match {
case sve: SingleValueExpression => FromScala(sve)
case mve: MultipleValueExpression => FromScala(mve)
}
filters ++ fromScala.transform(ToJson.string)
You can alternatively use # to do extraction and binding in one case (e.g. you want to match based on a component of a case class but save the overall match):
case sve # SingleValueExpression(value, _, _) if somePredicate(value) =>
// sve is the overall SingleValueExpression, and value is also available in this branch
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
i have a list of the following scala trait. How can i separate the list into two, one containing only ValidatedSbcCommand objects and other only containing FailedValidationSbcCommand objects?
sealed trait SbcCommandorOrValidationError
case class ValidatedSbcCommand(sbcCommand: SbcCommand) extends SbcC ommandorOrValidationError
case class FailedValidationSbcCommand(sbcCommandError: SbcCommandError) extends SbcCommandorOr
Use the partition method on list. It takes a predicate and produces a (List, List) The first list is for the true case the second is for false.
val result = originalList.foldRight(Tuple2(List[ValidatedSbcCommand](), List[FailedValidationSbcCommand]())){ (start, rest) =>
start match {
case a:ValidatedSbcCommand => (a::rest._1, rest._2)
case b:FailedValidationSbcCommand => (rest._1, b::rest._2)
case _ => rest
}
}
Then result._1 will give you a list of ValidatedSbcCommand, and result._2 will give you a list of FailedValidationSbcCommand.
I prefer using partition with pattern matching. Given list is of type List[SbcCommandorOrValidationError] and contains only ValidatedSbcCommands and FailedValidationSbcCommands, you can do this:
val (validatedCommands, failedCommands) = list.partition {
case command: ValidatedSbcCommand => true
case _ => false
}
This will return a tuple of type (List[SbcCommandorOrValidationError], List[SbcCommandorOrValidationError]) where the first list is all the ValidatedSbcCommands and the second is all the FailedValidationSbcCommands.
If you need to access the specific subclass later on, don't cast. Use pattern matching as above:
validatedCommands.map {
case c: ValidatedSbcCommand => functionTakingValidatedSbcCommandsOnly(c)
}
From Scala 2.13, you can use of partitionMap, which does exactly what you want, keeping the subtype info:
list partitionMap {
case v: ValidatedSbcCommand => Left(v)
case f: FailedValidationSbcCommand => Right(f)
}
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")
When doing pattern matching in an Akka or Scala Actor, is there a way to see what the match was NOT (i.e.) what is being evaluated by the wildcard _? Is there a simple way to see which message is being processed from the mailbox that it can't find a match for?
def receive = {
case A =>
case B =>
case C =>
...
case _ =>
println("what IS the message evaluated?")
}
Thanks,
Bruce
You can just define variable like this:
def receive = {
case A =>
case B =>
case C =>
...
case msg =>
println("unsupported message: " + msg)
}
You can even assign names to the messages that you are matching with #:
def receive = {
case msg # A => // do someting with `msg`
...
}
The "correct" way to do this in Akka is to override the "unhandled"-method, do what you want, and either delegate to the default behavior or replace it.
http://akka.io/api/akka/2.0-M4/#akka.actor.Actor
As for pattern matching in general, just match on anything, and bind it to a name, so you can refer to it:
x match {
case "foo" => whatever
case otherwise => //matches anything and binds it to the name "otherwise", use that inside the body of the match
}