Is it possible to match on a comparison using the pattern matching system in Scala? For example:
a match {
case 10 => println("ten")
case _ > 10 => println("greater than ten")
case _ => println("less than ten")
}
The second case statement is illegal, but I would like to be able to specify "when a is greater than".
case x if x.size > 2 => ...
You can add a guard, i.e. an if
and a boolean expression after the pattern:
a match {
case 10 => println("ten")
case x if x > 10 => println("greater than ten")
case _ => println("less than ten")
}
Edit: Note that this is more than superficially different to putting an if
after the =>
, because a pattern won't match if the guard is not true.
As a non-answer to the question's spirit, which asked how to incorporate predicates into a match clause, in this case the predicate can be factored out before the match
:
def assess(n: Int) {
println(
n compare 10 match {
case 0 => "ten"
case 1 => "greater than ten"
case -1 => "less than ten"
})
}
Now, the documentation for scala.math.Ordering.compare(T, T)
promises only that the non-equal outcomes will be greater than or less than zero. Java's Comparable#compareTo(T)
is specified similarly to Scala's. It happens to be conventional to use 1 and -1 for the positive and negative values, respectively, as Scala's current implementation does, but one can't make such an assumption without some risk of the implementation changing out from underneath.
compare()
and compareTo()
don't specify 0, 1, and -1 as their codomain.
A solution that in my opinion is much more readable than adding guards:
(n compare 10).signum match {
case -1 => "less than ten"
case 0 => "ten"
case 1 => "greater than ten"
}
Notes:
Ordered.compare returns a negative integer if this is less than that, positive if greater, and 0 if equal.
Int.signum compresses the output from compare to -1 for a negative number (less than 10), 1 for positive (greater than 10), or 0 for zero (equal to 10).
While all the above and bellow answers perfectly answer the original question, some additional information can be found in the documentation https://docs.scala-lang.org/tour/pattern-matching.html , they didn't fit in my case but because this stackoverflow answer is the first suggestion in Google I would like to post my answer which is a corner case of the question above.
My question is:
How to use a guard in match expression with an argument of a function?
Which can be paraphrased:
How to use an if statement in match expression with an argument of a function?
The answer is the code example below:
def drop[A](l: List[A], n: Int): List[A] = l match {
case Nil => sys.error("drop on empty list")
case xs if n <= 0 => xs
case _ :: xs => drop(xs, n-1)
}
link to scala fiddle : https://scalafiddle.io/sf/G37THif/2 as you can see the case xs if n <= 0 => xs
statement is able to use n(argument of a function) with the guard(if) statement.
I hope this helps someone like me.
Scala's pattern matching allows you to define your own extractor. In this case, you can simply define a new extractor:
class GreaterThan(n: Int) {
def unapply(i: Int) = i > n
}
val GreaterThan10 = GreaterThan(10)
a match {
case 10 => ???
case GreaterThan10() => ???
case _ => ???
}
or just use pattern guards.
Success story sharing