Scala: string pattern matching - scala

The below code takes the first two character of string and check if pattern is "de" or None it returns None else it returns the Test("Found")
val s =Option("abc")
val t = s.map(_.take(2))
case class Test(id:String)
t match {
case Some("de") => None
case None => None
case _ => Test("Found")
}
Can anyone suggest a efficient solution for case matching

I think I get what you're asking so let me try this:
val condition = Option("abc").exists(_.toLower.take(2) == "de")
val output: Any = if(condition) Test("found") else None
The first portion returns false if the Option is None. It also returns false if the first two letters of the string are "de" in a case insensitive way.
The second portion returns either a None or a Test object. However, I want to point out that this results in an Any. Did you mean for it to return a Option[Test] type instead?

I assume, you meant Some(Test("Found")) in the last line of your snippet, judging from your comment to the other answer.
If so, this is what you are looking for:
t.filterNot(_.take(2) == "de").map(_ => Test("Found"))

Related

Is there a way to use match with boolean

I find using match more readable than if. If I have a boolean value, can I use it with match?
I usually do
if(!authorised) {...} else {..}
But I am unable to do
authorised match {
case ??? //what here??
}
You just need to use boolean literals:
authorised match {
case true => /*true case*/
case false => /*false case*/
}
Alternatively to pattern match, consider mouse which provides extension methods for booleans, for example, consider fold
authorised.fold("It is true", "It is false")
You can do this using
authorised match {
case true => ...
case false => ...
}
Note that pattern matching on boolean values is not very idiomatic in Scala, and you'd probably be better off using the standard if/else expression. The compiler will actually not manage to generate the same efficient code for the pattern match, as discussed in this answer. It's very common for Scala beginners to get over-enthusiastic with pattern matching and start using it everywhere, but in the case of plain booleans, it really makes sense to stick with if/else.
Side-note: Other answers have mentioned using a default clause like
authorised match {
case true => /*true case*/
case false => /*false case*/
case _ => /* default case */
}
This is unnecessary, as Boolean can only ever be true or false. Like all primitive types, they cannot be assigned null so the additional clause is useless and the compiler will justifiably warn you about it.
warning: unreachable code
case _ => /* default case */
You can simply write:
authorised match {
case true => ...
case false => ...
}
Although intellij suggests refactoring to if statement.
You can do like this:
authorised match {
case true => // true case
case false => // false case
case _ => // other case for exception or null
}

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.

Getting max from a case class List of nodes, returning Scala Option[List]

I have a case class Node that I have written, and create a list from it and I need to find the node that has maximum disk.
I wrote the below code, is there a better way of doing it? Also, in my actual production code, my "nodeList" variable will be not just Option[List[Node]] but Future[Option[List[Node]]]. I guess still the answer/code won't change much except for the fact that I will do a map/flatMap to go inside the future and do the same thing.
If anyone has a better suggestion to write below code more Scala way, please share your thoughts.
scala> case class Node(disk: Integer, name: String)
defined class Node
scala> val nodeList = Option(List(Node(40, "node1"), Node(200, "node3"),Node(60, "node2")))
nodeList: Option[List[Node]] = Some(List(Node(40,node1), Node(200,node3), Node(60,node2)))
scala> val maxDisk = nodeList match {
| case None => println("List is empty"); None
| case Some(lst) => {
| Some(lst.max(Ordering.by((_:Node).disk)))
| }
| }`
maxDisk: Option[Node] = Some(Node(200,node3))
Judging by the code you wrote, I'm not sure if you really should use Optional[List[Node]]. You seem to treat None as an empty List, and you don't check for the empty list in the Some case. You might want to see if just a plain List[Node] suits your use better (where None would become Nil, and Some(lst) is just lst, and the unused Some(Nil) case no longer exists to confuse anyone).
If you do keep Optional[List[Node]], I'd do it like this:
nodeList
.filterNot(_.isEmpty) // maxBy throws if the list is empty; check for it
.map(_.maxBy(_.disk)) // maxBy looks nicer than max(Ordering.by)
If you switch to List[Node], it's slightly uglier:
Some(nodeList)
.filterNot(_.isEmpty) // We're using the filter utility of Option here,
.map(_.maxBy(_.disk)) // so I wrap with Some to get access to filterNot.
You can use recursion with List pattern matching.
case class Node(disk: Integer, name: String)
val nodeList = Option(List(Node(40, "node1"), Node(200, "node3"),Node(60, "node2")))
def findMaxValue(list: List[Node]): Option[Node] = list match {
case Nil => None
case List(x) => Some(x)
case first :: second :: rest => if(first.disk > second.disk) findMaxValue(first::rest) else findMaxValue(second::rest)
}
val node:Option[Node] = findMaxValue(nodeList.getOrElse(Nil))
println(node.get.disk) //print 200

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

scala match expression avoiding code duplication

Say I am using a match expression to test a value that may or may not be in a Map object as follows:
map.get(key) match {
case Some(value) if (cond1(value)) => res1(value)
case Some(value) if (cond2(value)) => res2()
case None => res2()
case _ => // None of the above
}
As you can see I want to call the res2 in either case where I have a value for my key and it meets condition 2 or I have no value for key. Can anyone suggest a better construct that would avoid the duplicate calls to res2() in the sample above?
Thanks
Des
* Sorry I realised that the code sample was not quite correct and have updated accordingly. I only want to call res2 in the case where the value for the key meets cond2 OR there is NO entry for key.
I believe what you want is:
map.get(key) match {
case Some(value) if (cond1(value)) => res1(value)
case o: Option[String] if ( o.forall(cond2) ) => res2()
case _ =>
}
replacing [String] with whatever the type of key is.
The names of the methods on Option aren't always the most obvious; in maintaining functional purity they sacrifice clarity for us illiterati. In this case, the scaladoc for Option tells us that forall:
Returns true if this option is empty or the predicate p returns true
when applied to this scala.Option's value.
Without gard if that are only possibilities:
case Some(value) => if (cond1(value) ) res1(value) else res2()