We use pattern matching when we want to perform different computations based on some match or condition.
If you are familiar with switch statements, this is similar but a little more powerful.
Types of Pattern Matching Techniques
There are different types of pattern-matching techniques:
1. Wildcard Pattern
Wildcard pattern is referred to as the condition which is executed if all else fails. This is usually marked using “_” (underscore symbol).
val list = List("One", "Two", "Three")
list match {
case Nil => "Star Pattern"
case _ => "Wild card Pattern"
}
Output
val list: List[String] = List(One, Two, Three)
val res0: String = Wild card Pattern
2. Variable Pattern
val message = "Hello ! What's up "
message match {
case greet: String => s"$greet TGB Users"
}
Output
val message: String = "Hello ! What's up "
val res1: String = Hello ! What's up TGB Users
3. Constant Pattern
val ONE: Int = 1
val TWO: Int = 2
val THREE: Int = 3
def matcher(x: Int) {
x match {
case ONE => println("one")
case TWO => println("two")
case THREE => println("three")
case _ => println("many : Match case for Wildcard Pattern")
}
}
matcher(ONE)
matcher(TWO)
Output
val ONE: Int = 1
val TWO: Int = 2
val THREE: Int = 3
def matcher(x: Int): Unit
one
two
4. Constructor Pattern
case class Pet(name: String, animal: String)
val listOfPets = List(Pet("Ginger", "Dog"),
Pet("boo", "Cat"),
Pet("Tommy", "Dog"),
Pet("Bow", "Dog"))
listOfPets.map {
case Pet(name, "Dog") => s"$name is a Dog"
case _ => "The pet is not a Dog :)"
}
Output
class Person
class Pet
val listOfPets: List[Pet] = List(Pet(Ginger,Dog), Pet(boo,Cat), Pet(Tommy,Dog), Pet(Bow,Dog))
val res4: List[String] = List(Ginger is a Dog, The pet is not a Dog :), Tommy is a Dog, Bow is a Dog)
5. Sequence Pattern
def getListType(x: List[Any]) = {
x match {
case Nil => "Got an Empty List"
case List(10, _, _) => "Got a size three list, starting with 10"
case List(1, _*) => "Got a list starting with one"
case _ => "Fallen in default case"
}
}
getListType(List())
getListType(List(1, 2, 3))
getListType(List(10, 2, 0))
getListType(List(3, 4, 7, 1))
Output
def getListType(x: List[Any]): String
val res5: String = Got an Empty List
val res6: String = Got a list starting with one
val res7: String = Got a size three list, starting with 10
val res8: String = Fallen in default case
6. Tuple Pattern
val zippedValue1 = ("Gaurav", 1, 25)
val zippedValue2 = ("Mohit", 1, "25")
def decode(details: Any) = {
details match {
case (name: String, sr: Int, age: Int) => s"$name-------$sr-------$age"
case (name: String, sr: Int, age: String) => s"$name--------$sr"
}
}
decode(zippedValue1)
decode(zippedValue2)
Output:
val zippedValue1: (String, Int, Int) = (Gaurav,1,25)
val zippedValue2: (String, Int, String) = (Mohit,1,25)
def decode(details: Any): String
val res9: String = Gaurav-------1-------25
val res10: String = Mohit--------1
7. Typed Pattern
def returnWhatYouGet(valType: Any) = {
valType match {
case s: String => s"you gave me this string: $s"
case i: Int => s"thanks for the int: $i"
case f: Float => s"thanks for the float: $f"
case a: Array[Int] => s"an array of int: ${ a.mkString(",") }"
case as: Array[String] => s"an array of strings: ${ as.mkString(",") }"
case d: Pet => s"dog: ${ d.name }"
case list: List[_] => s"thanks for the List: $list"
case m: Map[_, _] => m.toString
}
}
returnWhatYouGet("Hi")
returnWhatYouGet(1)
returnWhatYouGet(listOfPets.head)
Output
def returnWhatYouGet(valType: Any): String
val res11: String = you gave me this string: Hi
val res12: String = thanks for the int: 1
val res13: String = dog: Ginger
8. Using Pattern Guard
abstract class Notification
case class Email(sender:String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
case Email(email, _, _) if importantPeopleInfo.contains(email) =>
"You got an email from special someone!"
case SMS(number, _) if importantPeopleInfo.contains(number) =>
"You got an SMS from special someone!"
case other => "Unknown Service"
// nothing special, delegate to our original showNotification function
}
}
val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")
println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))
Output
class Notification
class Email
class SMS
class VoiceRecording
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String
val importantPeopleInfo: Seq[String] = List(867-5309, jenny@gmail.com)
val someSms: SMS = SMS(867-5309,Are you there?)
val someVoiceRecording: VoiceRecording = VoiceRecording(Tom,voicerecording.org/id/123)
val importantEmail: Email = Email(jenny@gmail.com,Drinks tonight?,I'm free after 5!)
val importantSms: SMS = SMS(867-5309,I'm here! Where are you?)
You got an SMS from special someone!
Unknown Service
You got an email from special someone!
You got an SMS from special someone!
9. Sealed Class pattern
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
def findPlaceToSit(piece: Furniture): String = piece match {
case a: Couch => "Lie on the couch"
case b: Chair => "Sit on the chair"
}
Output
class Furniture
class Couch
class Chair
def findPlaceToSit(piece: Furniture): String