Spray routing filter path parameter - scala

given this snippet of code
val passRoute = (path("passgen" / IntNumber) & get) { length =>
complete {
if(length > 0){
logger.debug(s"new password generated of length $length")
newPass(length)
}
else {
logger.debug("using default length 8 when no length specified")
newPass(8)
}
}
}
How could I replace the if-else with a match-case pattern, eventually using also an Option object with Some-None.
My aim is to filter out the length and handle the case where length is an Int exists , it does not exist, is something else than an Int.
I have tried this but it does not work.
val passRoute = (path("passgen" / IntNumber) & get) { length =>
complete {
length match {
case Some(match: Int) => print("Is an int")
case None => print("length is missing")
//missing the case for handling non int but existent values
// can be case _ => print("non int") ???
}
}
}

My guess is that in your non-working code, length is still an Int, and hence does not match with either Some or None. If you wanted to translate your if-else code to a match-statement, I'd suggest something similar to the following code, which matches for positive Int values:
List(10, -1, 3, "hello", 0, -2) foreach {
case length: Int if length > 0 => println("Found length " + length)
case _ => println("Length is missing")
}
If you want to be fancy, you can also define a custom extractor:
object Positive {
def unapply(i: Int): Option[Int] = if (i > 0) Some(i) else None
}
List(10, -1, 3, "hello", 0, -2) foreach {
case Positive(length) => println("Found length " + length)
case _ => println("Length is missing")
}
And if you somehow do have Option values, the following should work:
List(10, -1, 3, "hello", 0, -2) map (Some(_)) foreach {
case Some(length: Int) if length > 0 => println("Found length " + length)
case _ => println("Length is missing")
}
All of those snippets print
Found length 10
Length is missing
Found length 3
Length is missing
Length is missing
Length is missing

Related

how to extract part of string that did not match pattern

I want to extract part of string that did not match pattern
My pattern matching condition is sting should be of length 5 and should contain only N or Y.
Ex:
NYYYY => valid
NY => Invalid , length is invalid
NYYSY => Invalid. character at position 3 is invalid
If string is invalid then I want to find out which particular character did not match. Ex : In NYYSY 4th character did not match.
I tried with pattern matching in scala
val Pattern = "([NY]{5})".r
paramList match {
case Pattern(c) => true
case _ => false
}
Returns a String indicating validation status.
def validate(str :String, len :Int, cs :Seq[Char]) :String = {
val checkC = cs.toSet
val errs = str.zipAll(Range(0,len), 1.toChar, -1).flatMap{ case (c,x) =>
if (x < 0) Some("too long")
else if (checkC(c)) None
else if (c == 1) Some("too short")
else Some(s"'$c' at index $x")
}
str + ": " + (if (errs.isEmpty) "valid" else errs.distinct.mkString(", "))
}
testing:
validate("NTYYYNN", 4, "NY") //res0: String = NTYYYNN: 'T' at index 1, too long
validate("NYC", 7, "NY") //res1: String = NYC: 'C' at index 2, too short
validate("YNYNY", 5, "NY") //res2: String = YNYNY: valid
Here's one approach that returns a list of (Char, Int) tuples of invalid characters and their corresponding positions in a given string:
def checkString(validChars: List[Char], validLength: Int, s: String) = {
val Pattern = s"([${validChars.mkString}]{$validLength})".r
s match {
case Pattern(_) => Vector.empty[(Char, Int)]
case s =>
val invalidList = s.zipWithIndex.filter{case (c, _) => !validChars.contains(c)}
if (invalidList.nonEmpty) invalidList else Vector(('\u0000', -1))
}
}
List("NYYYY", "NY", "NNSYYTN").map(checkString(List('N', 'Y'), 5, _))
// res1: List(Vector(), Vector((?,-1)), Vector((S,2), (T,5)))
As shown above, an empty list represents a valid string and a list of (null-char, -1) means the string has valid characters but invalid length.
Here is one suggestion which might suit your needs:
"NYYSY".split("(?<=[^NY])|(?=[^NY])").foreach(println)
NYY
S
Y
This solution splits the input string at any point when either the preceding or following character is not a Y or a N. This places each island of valid and invalid characters as separate rows in the output.
You can use additional regular expressions to detect the specific issue:
val Pattern = "([NY]{5})".r
val TooLong = "([NY]{5})(.+)".r
val WrongChar = "([NY]*)([^NY].*)".r
paramList match {
case Pattern(c) => // Good
case TooLong(head, rest) => // Extra character(s) in sequence
case WrongChar(head, rest) => // Wrong character in sequence
case _ => // Too short
}
You can work out the index of the error using head.length and the failing character is rest.head.
You can achieve this with pattern matching each characters of the string without using any sort of regex or complex string manipulation.
def check(value: String): Unit = {
if(value.length!=5) println(s"$value length is invalid.")
else value.foldLeft((0, Seq[String]())){
case (r, char) =>
char match {
case 'Y' | 'N' => r._1+1 -> r._2
case c # _ => r._1+1 -> {r._2 ++ List(s"Invalid character `$c` in position ${r._1}")}
}
}._2 match {
case Nil => println(s"$value is valid.")
case errors: List[String] => println(s"$value is invalid - [${errors.mkString(", ")}]")
}
}
check("NYCNBNY")
NYNYNCC length is invalid.
check("NYCNB")
NYCNB is invalid - [Invalid character `C` in position 2, Invalid character `B` in position 4]
check("NYNNY")
NYNNY is valid.

How to avoid return in scala

I have an example like this one:
def demo(a: Int, b: Int, c:Int): Int = {
if (a == 1)
return 10
if (b == 2)
return 20
if (c == 3)
return 30
40
}
The code works well, but I know in Scala we try to avoid the return. So I would like to ask there are any different way we can avoid the return?
Thank you
Edited
This is the real case I got, and I would like to avoid the return.
post("/") {
if (product_id <= 0)
return BadRequest(Map("ERROR" -> "PRODUCT_ID IS WRONG"))
if (file_id.isEmpty())
return BadRequest(Map("ERROR" -> "FILE ID NOT FOUND"))
if (data_type.isEmpty())
return BadRequest(Map("ERROR" -> "FILE TYPE NOT FOUND"))
if (data_type.get != "cvs")
return BadRequest(Map("ERROR" -> "FILE TYPE IS WRONG"))
OK(Map("SUCCESS" -> "THANK YOU"))
}
The basic option would be to use if else:
if (a == 1) 10 else if (b == 2) 20 else if (c == 3) 30 else 40
Another option is to use pattern matching:
def demo(a: Int, b: Int, c: Int): Int = (a, b, c) match {
case (1, _, _) => 10
case (_, 2, _) => 20
case (_, _, 3) => 30
case _ => 40
}
You can do something like that, for large number of parameters:
def demo(ints: Int*) =
ints.foldLeft((0, 1, 40)) { (acc, i) =>
if (acc._2 == i && acc._1 == 0) (1, acc._2, i * 10)
else (acc._1, acc._2 + 1, acc._3)
}._3
I am not sure it is easy to read, but if you have many arguments maybe it is something to consider.
Some explanations: In the foldLeft we start with the (0, 1, 40) 0 is an indicator if we found value to return, 1 is an index in ints, and 40 is the result, if found another value to be returned it will be replaced. If "demo" is just a simple way to explain another problem you have, you should replace the condition and it's result according to your real problem.

Scala: Make sure braces are balanced

I am running a code to balance brackets in statement. I think i have gotten it correct but it is failing on one particular statement, i need to understand why?
This is the test in particular it is failing "())("
More than the coding i think i need to fix the algo, any pointers?
def balance(chars: List[Char]): Boolean = {
def find(c: Char, l: List[Char], i: Int): Int={
if( l.isEmpty ) {
if(c=='(')
i+1
else if(c==')')
i-1
else
i
}
else if (c=='(')
find(l.head, l.tail, i+1)
else if(c==')')
find(l.head,l.tail, i-1)
else
find(l.head,l.tail, i)
}
if(find(chars.head, chars.tail,0) ==0 )
true
else
false
}
balance("())(".toList) //passes when it should fail
balance(":-)".toList)
balance("(if (zero? x) max (/ 1 x))".toList)
balance("I told him (that it's not (yet) done).\n(But he wasn't listening)".toList)
Here is a version:
def balance(chars: List[Char]): Boolean = {
def inner(c: List[Char], count: Int): Boolean = c match {
case Nil => count == 0 // Line 1
case ')' :: _ if count < 1 => false // Line 2
case ')' :: xs => inner(xs, count - 1) // Line 3
case '(' :: xs => inner(xs, count + 1) // Line 4
case _ :: xs => inner(xs, count) // Line 5
}
inner(chars, 0)
}
So in your code, I think you are missing the additional check for count < 1 when you encounter the right paranthesis! So you need an additional else if that checks for both the ')' and count < 1 (Line 2 in the example code above)
Using map:
def balance(chars: List[Char]): Boolean = {
chars.map(c =>
c match {
case '(' => 1
case ')' => -1
case _ => 0
}
).scanLeft(0)(_ + _).dropWhile(_ >= 0).isEmpty
}
You've made a very simple and completely understandable mistake. The parentheses in )( are balanced, by your current definition. It's just that they're not balanced in the way we would usually think. After the first character, you have -1 unclosed parentheses, and then after the second characte we're back to 0, so everything is fine. If the parenthesis count ever drops below zero, the parentheses cannot possibly be balanced.
Now there are two real ways to handle this. The quick and dirty solution is to throw an exception.
case object UnbalancedException extends Exception
if (i < 0)
throw UnbalancedException
then catch it and return false in balance.
try {
... // find() call goes in here
} catch {
case UnbalancedException => false
}
The more functional solution would be to have find return an Option[Int]. During the recursion, if you ever get a None result, then return None. Otherwise, behave as normally and return Some(n). If you ever encounter the case where i < 0 then return None to indicate failure. Then in balance, if the result is nonzero or the result is None, return false. This can be made prettier with for notation, but if you're just starting out then it can be very helpful to write it out by hand.
You can also use the property of Stack data structure to solve this problem. When you see open bracket, you push it into the stack. When you see close bracket, you pop from the stack (instead of Stack I'm using List, because immutable Stack is deprecated in Scala):
def isBalanced(chars: Seq[Char]): Boolean = {
import scala.annotation.tailrec
case class BracketInfo(c: Char, idx: Int)
def isOpen(c: Char): Boolean = c == '('
def isClose(c: Char): Boolean = c == ')'
def safePop[T](stack: List[T]): Option[T] = {
if (stack.length <= 1) stack.headOption
else stack.tail.headOption
}
#tailrec
def isBalanced(chars: Seq[Char], idx: Int, stack: List[BracketInfo]): Boolean = {
chars match {
case Seq(c, tail#_*) =>
val newStack = BracketInfo(c, idx) :: stack // Stack.push
if (isOpen(c)) isBalanced(tail, idx + 1, newStack)
else if (isClose(c)) {
safePop(stack) match {
case Some(b) => isBalanced(tail, idx + 1, stack.tail)
case None =>
println(s"Closed bracket '$c' at index $idx was not opened")
false
}
}
else isBalanced(tail, idx + 1, stack)
case Seq() =>
if (stack.nonEmpty) {
println("Stack is not empty => there are non-closed brackets at positions: ")
println(s"${stack.map(_.idx).mkString(" ")}")
}
stack.isEmpty
}
}
isBalanced(chars, 0, List.empty[BracketInfo])
}

passing variable argument data type to a scala method

I want to create a method/function in scala which can take variable arguments of type string or int and return the result of type String or Int.
def Hello(name: String, Param: int*/string*): Int/String= {
var index = 0
while(index < Param.length) {
var n = name
var ar = Param(index)
if ( n.equals(ar) ) return Param(index + 1)
else index = index + 1
}
return Param(index.length -1)
}
If we call the Hello function then it should return the result as given below.
val Res1 = Hello("Jack", "rakesh", 1, "Jack", 2, "No one")
println(Res1)
=> this should return value 2
val Res2 = Hello("ABC", "rakesh", 1, "Jack", 2, "Vik", 3, "ram", 4, "No one")
println(Res2)
=> this should return value "No one"
Using Any should work:
def hello(name: Any, param: Any*): Any= {
var list = param.dropWhile(_ != name)
list.drop(1).headOption.orElse(param.lastOption).getOrElse("")
}
Depending on how type safe you want it to be, you can try to use generics or other means to restrict the types used. Or you can just pattern match the response type:
hello("ABC", "rakesh", 1, "Jack", 2, "Vik", 3, "ram", 4, "No one") match {
case i: Int => println("Got a int:" + i)
case s: String=> println("Got a string:" + s)
}
This will help you
def Hello( name: String,args: Any* ) = {
val index = args.indexOf(name)
if(index == -1)
args(args.length - 1)
else
args(index + 1)
}
Your whole approach is faulty, but here's how it can be done in a type-safe manner.
def Hello(name: String, param: Either[Int,String]*): Either[Int,String] = {
param.sliding(2,2)
.find(_(0).fold(_ => false, _ == name))
.fold(param.last)(_(1))
}
Usage:
Hello("Jack", Right("rakesh"), Left(1), Right("Jack"), Left(2), Right("No one"))
// res0: Either[Int,String] = Left(2)
Hello("ABC", Right("rakesh"), Left(1), Right("Jack"), Left(2),
Right("Vik"), Left(3), Right("ram"), Left(4), Right("No one"))
// res1: Either[Int,String] = Right(No one)
But it would be better to rethink it from the ground up.
I believe, what you want to achieve, is to get an index of a String element(if start counting from 1) in varargs, or return "No one". No need to pass indices to the method. You can do it like this:
def hello(name: String, params: String*): Any = {
val idx = params.indexOf(name)
if (idx != -1) idx + 1 else "No One"
}
Unfortunately both this:
def Hello(name: String, args: Any* ) = {
val index = args.indexOf(name)
if(index == -1)
args(args.length - 1)
else
args(index + 1)
}
and this:
def hello(name: String, param: Any*): Any= {
var index = 0
while(index < param.length) {
var n = name
var ar = param(index)
if ( n.equals(ar) ) return param(index + 1)
else index = index + 1
}
param(index -1)
}
are broken, as they throw an exception if you try to find the index of "No one", as index + 1 will equal to the size of the array. And it's better to compare things in Scala with == for logical equality.
But it's better not to return Any at all, but return Option[Int]:
def hello(name: String, params: String*): Option[Int] =
Option(params.indexOf(name)).filter(_ != -1).map(_ + 1)
So then you can use it like this:
val message1 = hello("Jack", "rakesh" ,"Jack").getOrElse("No one")
val message2 = hello("ABC", "rakesh", "Jack", "Vik", "ram").getOrElse("No one")
Answering the comment:
I want to know how can i pass mixed datatypes to "param".
The simplest way is to have them all of type Any
and also get string or integer as return type
The same way, defining return type as Any
The only small issue here, is that there will be no compile time check against other types. E.g. somebody might pass Boolean or any complex object along with String's and Int's to your function. But you can check at runtime against it or play with types to limit them. I don't know your requirement here, maybe it's even advantage for you.
If having Any is fine, then I would solve it like this:
def Hello(name: Any, params: Any*): Any = Option(params)
.withFilter(_.nonEmpty)
.map(_.indexOf(name))
.filter(i => i != -1 && i < params.length - 1)
.map(i => params(i + 1))
.getOrElse("No one")
Or, if you can assume, params are never empty and you have to use the last param as the default, instead of just hard coded "No one":
def Hello(name: Any, params: Any*): Any = Option(params)
.withFilter(_.nonEmpty)
.map(_.indexOf(name))
.filter(i => i != -1 && i < params.length - 1)
.map(i => params(i + 1))
.getOrElse(params.last)
Notice the check against "No one" attack: i < params.length - 1.
Notice that name now is also of type Any.
Now, even if you pass "No one" as a name, the Option will evaluate to None thanking to the filter, and getOrElse will give you the default "No one" instead of an exception.

Why does scala complain when given this pattern match on an integral value?

Goal: Write a function that generates a new String excluding a specified character (identified by the index)
Example:
takeAllExcept(0, "abc") returns bc
takeAllExcept(1, "abc") returns ac
takeAllExcept(2, "abc") returns ab
What I did initially:
def takeAllExcept( index: Int, s: String ): String = {
val lastIndex = s.length()-1
index match {
case 0 => return s.slice(1, s.length)
case lastIndex => return s.slice(0, s.length()-1)
case _ => { s.slice(0, index) + s.slice(index+1, s.length) }
}
}
The compiler complains that the statement block for case _ is unreachable.
How I fixed it
def takeAllExcept( index: Int, s: String ): String = {
val lastIndex = s.length()-1
if( index == 0 )
return s.slice(1, s.length)
if( index == lastIndex )
return s.slice(0, s.length()-1)
s.slice(0, index) + s.slice(index+1, s.length)
}
I want to know why my initial attempt failed with the unreachable code. It looks legit to me. Also, is there an in-built facility in scala that already does this ?
lastIndex in the pattern is an implicit declaration of a new name that is bound to whatever value is put into the match and shadows the allready defined lastIndex, as the other two post allready pointed out. There are two other possibilities instead of using upper case identifiers (see Peter's post):
Using backticks to let the compiler know that this shall not be a declaration of a new identifier:
case `lastIndex` => ...
Using pattern guards:
case x if x == lastIndex => ...
If you want to do a lot of index-based removing on strings then it would be faster to use a Buffer by calling toBuffer on the string and then you can use the remove(i: Int) method of Buffer. That is slower for only one operation because you will have to convert the Buffer back to string when your done but if you do many random access operations its a lot faster. After your done you can call mkString on the Buffer to get your String back. For single removal I would do it like Peter suggested or here is an alternative:
def takeAllExcept(i: Int, s: String) = s.take(i) + s.drop(i+1)
Your first question:
def takeAllExcept( index: Int, s: String ): String = {
val LastIndex = s.length()-1
index match {
case 0 => return s.slice(1, s.length)
case LastIndex => return s.slice(0, s.length()-1)
case _ => { s.slice(0, index) + s.slice(index+1, s.length) }
}
}
The lastIndex after the case is newly bound while pattern matching and hides the definition of val lastIndex = s.length()-1. As my example shows, you can use upper case names, then scala uses a defined val in scope.
To answer your second question in a way I would solve it:
def takeAllExcept(i: Int, s: String): String = {
val (prefix,suffix) = s.splitAt(i)
prefix + suffix.tail
}
val lastIndex = s.length()-1
index match {
case 0 => return s.slice(1, s.length)
case lastIndex => return s.slice(0, s.length()-1)
case _ => { s.slice(0, index) + s.slice(index+1, s.length) }
}
The second clause does not try to match index with lastIndex as you would have expected from e.g. Prolog. Instead it matches any value and binds the value to the name lastIndex, shadowing the previous binding of this variable.