Scala Pattern Matching using Option[Type] - scala

I am playing around with Scala at the moment and the pattern matching. I have the general idea behind it and can get the basics working. My issue is with Option[]. It is possible to use pattern matching on Option[]'s?
What I am trying to do is make a little function that will take in an option[String] parameter and then based on the input return the string if its a string and a heads up if not. I am not too sure on how to go about this though, I have tried a few thing but it either gives out or in the case below will never hit the second case.
def getString(someString: Option[String]): String =
someString match {
case s: Option[String] => someString //also tried things like case: String => ...
case _ => s"no string entered" //and things like case _ => ...
}

This is the easiest way to implement your function:
def getString(someString: Option[String]): String =
someString.getOrElse("no string entered")
If you want to use match it looks like this:
def getString(someString: Option[String]): String =
someString match {
case Some(s) => s
case _ => "no string entered"
}

Related

Typecasting in Scala

I have an alphanumeric field in an RDD of type AnyRef.
Case1: If it's 99898, I want to cast it as Long
Case2: If it's 0099898, I want to cast it as String
Case3: If it's AB998, I want to cast it as String.
I am trying this:
try {
account_number.asInstanceOf[ Long ])
} catch {
case _: Throwable => account_number.asInstanceOf[ String ])
}
But in this, I miss the case2, because 0099898 is converted to 99898. Any ideas?
If this field is AnyRef I wouldn't expect AnyVals there at all (like Long) - Scala's numbers are not equal to Java's numbers. At best you can have there some instance of java.lang.Numeric (e.g. java.lang.Long which is NOT scala.Long).
But to turn it into Long you would have to use pattern matching (with type matching or regexp pattern matching) and conversion (NOT casting!) to
val isStringID = raw"(0[0-9]+)".r
val isLongID = raw"([0-9]+)".r
account_number match {
case isStringID(id) => id // numeric string starting with 0
case isLongID(id) => id.toLong // numeric string convertible to Long
case l: java.lang.Long => l.toLong // Java's long
case _ => throw new IllegalArgumentException("Expected long or numeric string")
}
However, I would find that completely useless - right now you have Any instead of AnyVal. You could expect it to have Long or String but it's not represented by the returned value so compiler would NOT have any information about the safe usages. Personally, I would recommend doing something imediatelly after matching e.g. wrapping it with Either or creating ADT or passing it to function which needs String or Long.
// can be exhaustively pattern matched, or .folded or passed, etc
val stringOrLong: Either[String, Long] = account_number match {
case isStringID(id) => Left(id)
case isLongID(id) => Right(id.toLong)
case l: java.lang.Long => Right(l.toLong)
case _ => throw new IllegalArgumentException("Expected long or numeric string")
}
You cannot use .asInstanceOf to turn AnyRef to Long because neither is subtype or supertype of another, and this operation would always fail.
Any
/ \
AnyVal AnyRef
| |
Long |
\ /
Nothing
.asInstanceOf would only make sense if you were moving vertically in this hierarchy, not horizontally.
Another option you have is:
def tryConvert(s: String): Either[Long, String] = {
Try(s.toLong).filter(_.toString == s) match {
case Success(value) =>
Left(value)
case Failure(_) =>
Right(s)
}
}
Code run at Scastie.

Scala calculator that accepts three string parameters

How to write a method called calculator that accepts three string parameters:
def calculator(operand1: String, operator: String, operand2: String): Unit
Converts the operands to Int;
Performs the desired mathematical operator (+, -, *, or /) on the two operands
Prints the result, or a generic error messages
Your question shows that you put little to no effort into finding the solution yourself.
When asking a question on StackOverflow next time, ask a question about existing code (e.g. "Why am I getting this exception?" or "Why doesn't my code compile?") and don't assume some internet code monkey will magically write your code.
Anyways, as you seem to be a new member of SO, def calculator would look something like this:
import scala.collection.immutable.StringOps._
import scala.util.{Try, Success, Failure}
def calculator(left: String, op: String, right: String): Unit = {
def parse(value: String) = Try(value.toDouble)
(parse(left), parse(right)) match {
case (Success(leftDouble), Success(rightDouble)) => {
op match {
case "/" => println(leftDouble / rightDouble)
case "*" => println(leftDouble * rightDouble)
case "+" => println(leftDouble + rightDouble)
case "-" => println(leftDouble - rightDouble)
case invalid: String => println(s"Invalid operator $invalid.")
}
}
case (Failure(e), _) => println(s"Could not parse $left.")
case(_, Failure(e)) => println(s"Could not parse $right.")
case(Failure(e1), Failure(e2)) => println(s"Could not parse $left and $right.")
}
}
Try it out!
If you need any explanation don't hesitate to drop a comment.
I hope this helps.

Take first three letters in the string

I need to retrieve first three letters
val s ="abc"
val t = s.substring(0,2).equals("ab")
case class Test(id :String)
if(t){
Test("found")
}else{
None
}
Is there a efficient way to code for the above logic
"abc".take(2) match {
case "ab" => Test("found")
case _ => None
}
for String, you can use take to get chars like Seq, and it's more safe than substring to avoid StringIndexOutOfBoundsException exception.
and since you are returning None when not match, Test("found") Shouldn't be Some(Test("found"))?
One-liner:
case class Test(id: String)
val s = "abc"
if (s.take(2) == "ab") Test("found") else None
Make sure your string is at least 2 characters long or take will throw an exception.

Scala: Shorthand for pattern match on type?

Is there a more elegant way of doing the following?
data match {
case e: SomeType => doSomethingWith(e)
case _ =>
}
Looking for something like:
data.ifInstanceOf[SomeType](doSomethingWith)
Do you want an expression or just perform a side-effect? If just a side-effect via "PimpMyLibrary" approach + refection:
import scala.reflect.ClassTag
implicit class AnyOps(data : Any) {
def ifInstanceOf[A : ClassTag](f: A => Unit) : Unit = {
val clzz = implicitly[ClassTag[A]].runtimeClass
if (clzz.isInstance(data)) f(data.asInstanceOf[A])
}
}
You can then try
"abc".ifInstanceOf[String](println)
"def".ifInstanceOf[Integer](println)
1.ifInstanceOf[Integer](println)
2.ifInstanceOf[String](println)
If you want an expression I think the best way to go is to add an additional type Parameter B and return Either[B, Anyref].
I think a collect might work for this. The method takes a partial function, and filters out elements that did not match any case statements:
Option(data) collect {
case element: SomeType => mappingFunction(element)
}
Of course, mappingFunction here could have side effects and return Unit, thereby mimicking a foreach.
If you want to make a new named method, you could make a new method on Any:
implicit class AnyOps(data: Any) {
def forMatch[A](pf: PartialFunction[Any, A]) = pf.lift(data)
}
For some reason, this didn't come up:
import PartialFunction._
condOpt("abc": Any) { case s: String => s.length } // = Some(3)
condOpt((): Any) { case s: String => s.length } // = None
I usually rename it or its sibling cond to when.
You can use asInstanceOf to get your goal:
Option(data)
.filter(_.isInstanceOf[SomeType])
.map(_.asInstanceOf[SomeType])
.map(doSomethingWith)
but I guess it's too verbose.
I think you'll find it difficult to find anything shorter or more precise than "good old"...
if (data.isInstanceOf[SomeType]) doSomething(data)
... unless your case is more complicated than you're showing

Can extractors be customized with parameters in the body of a case statement (or anywhere else that an extractor would be used)?

Basically, I would like to be able to build a custom extractor without having to store it in a variable prior to using it.
This isn't a real example of how I would use it, it would more likely be used in the case of a regular expression or some other string pattern like construct, but hopefully it explains what I'm looking for:
def someExtractorBuilder(arg:Boolean) = new {
def unapply(s:String):Option[String] = if(arg) Some(s) else None
}
//I would like to be able to use something like this
val {someExtractorBuilder(true)}(result) = "test"
"test" match {case {someExtractorBuilder(true)}(result) => result }
//instead I would have to do this:
val customExtractor = someExtractorBuilder(true)
val customExtractor(result) = "test"
"test" match {case customExtractor(result) => result}
When just doing a single custom extractor it doesn't make much difference, but if you were building a large list of extractors for a case statement, it could make things more difficult to read by separating all of the extractors from their usage.
I expect that the answer is no you can't do this, but I thought I'd ask around first :D
Parameterising extractors would be cool, but we don't have the resources to implement them right now.
Nope.
8.1.7 Extractor Patterns
An extractor pattern x (p 1 , . . . ,
p n ) where n ≥ 0 is of the same
syntactic form as a constructor
pattern. However, instead of a case
class, the stable identifier x denotes
an object which has a member method
named unapply or unapplySeq that
matches the pattern.
One can customize extractors to certain extent using implicit parameters, like this:
object SomeExtractorBuilder {
def unapply(s: String)(implicit arg: Boolean): Option[String] = if (arg) Some(s) else None
}
implicit val arg: Boolean = true
"x" match {
case SomeExtractorBuilder(result) =>
result
}
Unfortunately this cannot be used when you want to use different variants in one match, as all case statements are in the same scope. Still, it can be useful sometimes.
Late but there is a scalac plugin in one of my lib providing syntax ~(extractorWith(param), bindings):
x match {
case ~(parametrizedExtractor(param)) =>
"no binding"
case ~(parametrizedExtractor(param), (a, b)) =>
s"extracted bindings: $a, $b"
}
https://github.com/cchantep/acolyte/blob/master/scalac-plugin/readme.md
Though what you are asking isn't directly possible,
it is possible to create an extractor returning a contaner that gets evaluated value in the if-part of the case evaluation. In the if part it is possible to provide parameters.
object DateExtractor {
def unapply(in: String): Option[DateExtractor] = Some(new DateExtractor(in));
}
class DateExtractor(input:String){
var value:LocalDate=null;
def apply():LocalDate = value;
def apply(format: String):Boolean={
val formater=DateTimeFormatter.ofPattern(format);
try{
val parsed=formater.parse(input, TemporalQueries.localDate());
value=parsed
true;
} catch {
case e:Throwable=>{
false
}
}
}
}
Usage:
object DateExtractorUsage{
def main(args: Array[String]): Unit = {
"2009-12-31" match {
case DateExtractor(ext) if(ext("dd-MM-yyyy"))=>{
println("Found dd-MM-yyyy date:"+ext())
}
case DateExtractor(ext) if(ext("yyyy-MM-dd"))=>{
println("Found yyyy-MM-dd date:"+ext())
}
case _=>{
println("Unable to parse date")
}
}
}
}
This pattern preserves the PartialFunction nature of the piece of code. I find this useful since I am quite a fan of the collect/collectFirst methods, which take a partial function as a parameter and typically does not leave room for precreating a set of extractors.