Scala Syntax - Pattern Matching
Pattern matching in Scala is powerful in matching constants
, extract element
, casting type
pattern matching basics
def numberToLiteral(i: Int) : String = {
i match {
case 1 => "one"
case 2 => "two"
case _ => "other"
}
}
println(numberToLiteral(1))
// one
println(numberToLiteral(5))
// other
def example2(i: Int) : Int = {
i match {
case 0 | 1 => 0
case n => n - 1
}
}
example2(3)
// res52: Int = 2
example2(1)
// res53: Int = 0
def example3(i: Int) : Int = i match {
case n if n <= 1 => 1
case 2 => 2
case n => example3(n - 1) + n
}
match data types
val elements = List("word", 1.23, 3, 'C')
for (e <- elements) {
e match {
case x: Int => println(s"Integer $x")
case x: String => println(s"String $x")
case x: Double => println(s"Double $x")
case other => println(s"other: $other")
}
}
// String word
// Double 1.23
// Integer 3
// other: C
def moreTests(o: Any) = o match {
case s: String => s"${s.length} chars in the string"
case i: Int if i > 0 => s"Got a positive integer: $i"
case i: Int => s"a small number"
case o: AnyRef => s"Got an object of ${o.getClass.getName}"
case _ => "something else"
}
moreTests(2)
// res61: String = Got a positive integer: 2
moreTests(-1)
// res62: String = a small number
moreTests('a')
// res63: String = Got an object of java.lang.Character
moreTests("xyz")
// res64: String = 3 chars in the string
// List matching
val x = 1
val rest = List(2,3,4)
(x :: rest) match {
case Nil => println("nothing in list")
case head :: rest => println(s"head:$head, and rest:$rest")
}
// List matching - more
def sumByCondition(in: List[Int]): Int = in match {
case Nil => 0
case x :: rest if x % 3 == 0 => x + sumByCondition(rest)
case _ :: rest => sumByCondition(rest)
}
import scala.language.postfixOps
val mylist = 1 to 20 toList
sumByCondition(mylist)
// res2: Int = 63
def dropUnorderedItems(in: List[Int]): List[Int] = in match {
case Nil => Nil
case e1 :: e2 :: rest if e2 < e1 => dropUnorderedItems(e1 :: rest)
case e1 :: rest => e1 :: dropUnorderedItems(rest)
}
val mylist = List(1,3,7,4,9,13,12,15,8)
dropUnorderedItems(mylist)
// res4: List[Int] = List(1, 3, 7, 9, 13, 15)
usage with case-class
case class Car(name: String, speed: Int, brand: String)
val c1 = Car("PG308", 120, "Peugeot")
val c2 = Car("X3", 110, "BMW")
val c3 = Car("X5", 150, "BMW")
def fastCarName(c: Car) : Option[String] = c match {
case Car(name, speed, "BMW") if speed > 130 => Some(name)
case _ => None
}
fastCarName(c2)
// res11: Option[String] = None
fastCarName(c3)
// res12: Option[String] = Some(X5)
pattern match as Function
val mylist = List("a", 1, "b", 2.3, 'X', "d")
mylist.filter(a => a match {
case s: String => true
case _ => false
})
// can also be:
mylist.filter{
case s: String => true
case _ => false
}
// res16: List[Any] = List(a, b, d)
// look inside the PartialFunction
val checkFruit = new PartialFunction[String, String] {
val fruits = Set("apple", "banana", "orange")
def apply(s: String) = s"$s is fruit"
def isDefinedAt(s: String) = fruits(s)
}
// another way to write PartialFunction
val checkAnimal: PartialFunction[String, String] = {
case s: String if Set("baby", "monkey", "tiger")(s) => s"$s is animal"
}
val things = Set("baby", "banana", "water", "hammer")
val checkAnimalAndFruit = checkFruit orElse checkAnimal
things collect { checkAnimal }
things collect { checkAnimalAndFruit }
//
// An other PartialFunction example
//
def greetingPeople(name: String)(helloMyFriends: PartialFunction[String, String]): String = {
if (helloMyFriends.isDefinedAt(name))
helloMyFriends(name)
else
s"Hi $name, you are not in my friends list"
}
val helloMyFriends: PartialFunction[String, String] = {
case s: String if Set("Lucy", "Jack")(s) => s"Hello my friend $s"
}
greetingPeople("Sam")(helloMyFriends)
// res69: String = Hi Sam, you are not in my friends list
greetingPeople("Lucy")(helloMyFriends)
// res72: String = Hello my friend Lucy
val helloUnwelcome: PartialFunction[String, String] = {
case s: String if Set("Micky", "Joe")(s) => s"Hey $s, you are not welcome"
}
val helloGoodAndBad = helloMyFriends orElse helloUnwelcome
greetingPeople("Micky")(helloGoodAndBad)
greetingPeople("Larry") { case s if s == "Larry" => s"$s is my name" }