SCALA PATTERN MATCHING, CONCEPTS AND IMPLEMENTATIONS Mustapha Michrafy PhD M. MICHRAFY & C. VALLIEZ Contact the authors : datascience.km@gmail.com datascience.km@gmail.com1 Cyril Valliez PhD - We thank Oussama Lachiri for helpful discussions.
Context This study was presented at the seminar « Data Science Principales, Tools and Applications » at Cermsem laboratory M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com2
Goal This study aims to present the pattern matching and its implementation with Scala M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com3
Prerequisite Knowledge of • Scala programming language • Functional programming notion M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com4
Agenda 1. Basic pattern matching 2. Pattern matching and for loop 3. Pattern alternative: operator « | » 4. Pattern guards 5. Pattern guards and logical operator OR 6. Pattern matching and recursive function 7. Pattern matching on type 8. Pattern matching on tuple 9. Pattern matching on Option 10. Pattern matching on Immutable Collection 11. Pattern matching on Immutable Map 12. Pattern matching on Immutable Set 13. Pattern matching on List 14. Pattern matching on case class 15. Nested Pattern Matching in Case Classes 16. Matching on regular expression M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com5
Basic pattern matching : switch-case def getChoicegetChoicegetChoicegetChoice(choicechoicechoicechoice: Int): String = choicechoicechoicechoice matchmatchmatchmatch { case 0 => "no" case 1 => "yes" case ____ => "error" } if choice = 0 then "no" else if choice = 1 then "yes" else then "error" Pattern matching getChoice(1) //> res0: String = yes getChoice(0) //> res1: String = no getChoice(3) //> res2: String = error Testing The wildcard pattern “_” matches any object whatsoever. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com6
Pattern matching and initialization val choicechoicechoicechoice = 0 var mesg ==== choicechoicechoicechoice match { case 0 => "no" case 1 => "yes" case _ => "error" } println(mesg) //> no We can use pattern matching for initializing a variable. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com7
Pattern matching and for loop val choiceschoiceschoiceschoices = List(0,1,10) for( choicechoicechoicechoice <- choices) { choice match { case 0 => println("no") case 1 => println("yes") case _ => println("error") } } //> no //> yes //>error We can use pattern matching with for loop M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com8
Pattern alternative: operator « | » def getChoicegetChoicegetChoicegetChoice(choicechoicechoicechoice: Int): String = choicechoicechoicechoice matchmatchmatchmatch { casecasecasecase 0000 =>=>=>=> """"no"no"no"no" casecasecasecase 1111 => "no"=> "no"=> "no"=> "no" case 2 => "yes" case ____ => "error" } if choice in {0,1} then "no" else if choice = 2 then "oui" else then "error" Pattern matching « | » : OR With “|” , we can have multiple tests on a single line def getChoicegetChoicegetChoicegetChoice(choicechoicechoicechoice: Int): String = choicechoicechoicechoice matchmatchmatchmatch { casecasecasecase 0000 | 1 =>| 1 =>| 1 =>| 1 => """"no"no"no"no" case 2 => "yes" case ____ => "error" } getChoice(0) //>res1: String = no getChoice(1) //>res2: String = no Testing M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com9
Pattern guards def sign(x:Double) : Byte = x match { case x if x < 0if x < 0if x < 0if x < 0 => -1 case x if x > 0if x > 0if x > 0if x > 0 => 1 case _ => 0 } -1 if x < 0 sing(x) = 1 if x > 0 0 sinon Pattern matching sign(0) //> res1: Byte = 0 sign(2) //> res2: Byte = 1 sign(-2) //> res3: Byte = -1 Testing A pattern guard comes after a pattern and starts with an if. If a pattern guard is present, the match succeeds only if the guard evaluates to true M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com10
Pattern guards and logical operator OR def OR(p:Boolean, q: Boolean) : Boolean = (p, q)(p, q)(p, q)(p, q) match { case (x, y) if x==true | y==trueif x==true | y==trueif x==true | y==trueif x==true | y==true => true case _ => false } OR(false, false) //> res1: Boolean = false OR(false, true) //> res2: Boolean = true p q p OR q T T T T F T F T T F F F If (p=T | q=T) then OR(p,q)=true else OR(p,q) =false Testing Pattern matching Transform multiple parameters into one tuple (p,q) M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com11 1 1
Pattern matching and recursive function 1 if n = 0 n*(n-1)! otherwise n! ==== def factorialfactorialfactorialfactorial(n: Int): Int = n match { case 0 => 1 case _ => n*factorialfactorialfactorialfactorial(n-1) } def factorialfactorialfactorialfactorial(n:Int) : Int = { def fcfcfcfc(n:Int, p:Int) : Int = ((((n,pn,pn,pn,p)))) match { case (0,c) => c case (m,c) => fc(m-1,p*m) } fcfcfcfc(n,1) } factorial(0) //> res 1: Int = 1 factorial(4) //> res 2: Int = 24 1 Using a tuple (n,p) 2 Initialize an accumulator p to 1 Tail-recursive function M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com12
Pattern matching on type def matchByTypematchByTypematchByTypematchByType(z: Any): String = z match { case b:Boolean => s"A boolean : $b" case d:Double => s"A double : $d" case _ => " Unknown type " } 1 2 3 1 If z is Boolean type, b takes its value. 2 If z is the type Double , d takes its value. 3 Use wildcard when z is neither a Boolean type nor a Double type A typed pattern x:T consists of a pattern variable x and a type pattern T. The type of x is the type pattern T, where each type variable and wildcard is replaced by a fresh, unknown type. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com13
Pattern matching on tuple def detectZeroInTupledetectZeroInTupledetectZeroInTupledetectZeroInTuple(x: Tuple2[Any,Any]):String = x match { case (0,0|(0,0)) => "Both values zero." case (0,b) => s"First value is 0 in (0,$b)" case (a, 0) => s"Second value is 0 in ($a, 0)" case _ => "Both nonzero : " + x } 1 The tuple pattern matches input in tuple form and enables the tuple to be decomposed into its constituent elements by using pattern matching variables for each position in the tuple. detectZeroInTuple((0,(0,0))) //> res1: String = Both values zero. detectZeroInTuple((0,0)) //> res2: String = Both values zero. detectZeroInTuple((0,11)) //> res3: String = First value is 0 in (0,11) 1 Match a first pattern if x=(0,0) or x=(0,(0,0)). M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com14
Pattern matching on Option def getValueOptiongetValueOptiongetValueOptiongetValueOption[Any](x:Option[Any]) : String = x match{ case Some(x) => s"Some $x" case None => "None " } 1 Option -sealed abstract class- represents optional values. Instances of Option are either an instance of SomeSomeSomeSome or the object None.None.None.None. getValueOption(Option("hello")) //> Some hello getValueOption(Option(null)) //> None getValueOption(Option(())) //> Some () getValueOption(Option(List(10,11))) //Some List(10, 11)) 1 Match a Some(x) if x represents an existing value. Option Some None c c o 2 Match a None if x represents a non-existing value. 2 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com15
Pattern matching on immutable collection import scala.collection.immutable._ def getTypegetTypegetTypegetType(x:Traversable[Any]) : String = x match{ case s:Set[Any] => s"A Immutable Set : $s" case q:Seq[Any] => s"A Immutable Seq : $q" case _ => "A Immutable Map : $x" } getType(Set(0,2,4)) //> A Immutable Set : Set(0, 2, 4) getType(1 to 3) //> Immutable Seq : Range(1, 2, 3) getType(HashMap[Int,Int](1->13)) //> A Immutable Map : Map(1 -> 13) 2 Match a pattern then the type of x is returned Iterable Set Map Seq t t t t traversable t 1 1 2 3 3 Match wildcard then type map is returned This hierarchy is valid for mutable and immutable collections M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com16
Pattern matching on Immutable Map import scala.collection.immutable._ def getTypeOfMapgetTypeOfMapgetTypeOfMapgetTypeOfMap(x:Map[Int,Int]) : String = x match{ case _:HashMap[Int,Int] => "A HashMap " case _:TreeMap[Int,Int] => "A TreeMap " case _ => "A ListMap " } getTypeOfMap(HashMap[Int,Int](1->12,2->10)) //>A HashMap getTypeOfMap(TreeMap[Int,Int](1->3,6->6)) //> A TreeMap getTypeOfMap(ListMap[Int,Int](1->13,6->16)) //> A ListMap 1 if x is neither a HashMap nor a TreeMap then x is a ListMap Map HashMap ListMap TreeMap t c c c This hierarchy is valid only for the immutable Map Map is a Trait and all (children) are implementation classes 1 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com17
Pattern matching on immutable Set import scala.collection.immutable._ import scala.collection.immutable.BitSet._ def getTypeOfSetgetTypeOfSetgetTypeOfSetgetTypeOfSet(x:Set[Int]) : String = x match{ case h:HashSet[Int] => "A HashSet " + (h.size,h.sum) case t:TreeSet[Int] => "A TreeSet " + (t.size,t.sum) case l:ListSet[Int] => "A ListSet " + (l.size,l.sum) case z:AnyRef => "type : " + z.getClass.getName } getTypeOfSet(new BitSet1(10)) //> type : scala.collection.immutable.BitSet$BitSet1 getTypeOfSet(HashSet(1,10,12)) //> A HashSet (3,23) getTypeOfSet(TreeSet(1,10)) //> A TreeSet (2,11) getTypeOfSet(ListSet(1,11,12)) //> A ListSet (3,24) Set HashSet ListSet BitSet t c c c This hierarchy is valid only for the immutable Set. The Set is a Trait. BitSet is an abstract class and all children are the class. TreeSet c SortedSet t The subclasses of the abstract class BitSet are BitSet1, BitSet2 and BitSetN M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com18
Pattern matching on List 1/2 def sizeListsizeListsizeListsizeList[A](ls : List[A]) : Int = ls match{ case Nil => 0 case _::q => sizeList(q) + 1 } The following function computes the length of a list. It is based on two constructors NilNilNilNil and “::”. sizeList(List()) //> res40: Int = 0 sizeList(List(1)) //> res41: Int = 1 sizeList(List(1,(1,2),3,4)) //> res42: Int = 4 1 If the list is empty, Nil, then we return 0. 2 If ls represents a no-empty list then the length of list is (1+length(q)), where q represents the tail of the list. 1 2 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com19
Pattern matching on List 2/2 def identifyListeidentifyListeidentifyListeidentifyListe(ls: List[Any]): String = ls match { case Nil => "empty list" case _::Nil => "list with single element" case _::_::Nil => "list has two elements" case _ => "list has at least tree elements" } All lists are built from two constructors : NilNilNilNil and “::”.... NilNilNilNil represents a empty list :::::::: builds a non empty list characterized by a head and a tail. identifyListe(Nil) //> empty list identifyListe(List((1,2))) //> list with single element identifyListe(List("Scala", 3)) //> list has two elements identifyListe(List(1,2,3)) //> list has at least tree elements M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com20
Pattern matching on case class case class PersonPersonPersonPerson(name: String, age: Int) def validateAgevalidateAgevalidateAgevalidateAge(p: Person): Option[String] = p match { case Person(name, age) if age > 18 => Some(s"Hi $name! age $age") case _ => None } Case classes are classes that get to String, hashCode, and equals methods automatically. It provide a recursive decomposition mechanism via pattern matching validateAge(Person("Alice", 19)) //> Some(Hi Alice! age 19) validateAge(Person("Bill", 15)) //> None 2 If the age is greater than18 , then we return the name and age of the person. 3 If the age of the person is less than 18 , then we return None. 2 3 1 1 We define a case class of a person with name and age. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com21
Nested Pattern Matching in Case Classes case class Address(street: String, city: String, country: String) case class Person(name: String, age: Int, address:Address) def checkPrscheckPrscheckPrscheckPrs(p: Person): Option[String] = p match { case Person(name, age, null) if age > 18 => Some(s"Hi $name! age $age") case Person(name, age, Address(_,_,ctr)) => Some(s"Hi $name! age $age $ctr") case _ => None } checkPrs(Person("Alice", 19,null)) //> Some(Hi Alice! age 19) checkPrs(Person("Bill", 15, Address("Scala Lane", "Chicago", "USA"))) //> Some(Hi Bill! age 15 USA) 2 If age > 18 & address = null, then we return the name and age of the person. 3 If the address != null then we return the name, age and the city of the person. 3 2 1 We define two case classes Address and Person. Person contains a subclass Address. 1 Case classes can contain other case classes, and the pattern matching can be nested. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com22
Matching on regular expression val email = """(.*)@(.*).(.*)""".r val date = """(dddd)-(dd)-(dd)""".r def checkPattern(x:String) : Option[String] = x match{ case email(name,domain,extension) => Some(s"$name $domain $extension") case date(year, month, day) => Some(s"$year $month $day") case _ => None } A regular expression is used to determine whether a string matches a pattern and, if it does, to extract or transform the parts that match. Scala supports regular expressions through Regex class available in the scala.util.matching package. 2 3 1 4 1 We define a regular expressions for email and date by using the method rmethod rmethod rmethod r2 3 If regex of email is matched then extract name, domain and extension 4 If regex of date is matched then extract year, month and day checkPattern("info@scala.fr") //> Some(info scala fr) checkPattern("2016-03-26") //> Some(2016 03 26) M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com23
References • Scala Language Specification, http://www.scala- lang.org/files/archive/spec/2.11/ • Documentation for the Scala standard library, http://www.scala-lang.org/api/current/ • Beginning Scala, by Vishal Layka, David Pollak, 2015 • Programming in Scala, by Martin Odersky and al., 2011 • Programming Scala, by Dean Wampler, Alex Payne, 2014 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com24
Mustapha Michrafy PhD Data Scientist and Expert Optim at ATOS Contact : datascience.km@gmail.com Cyril Valliez PhD Software Architect at Bouygues M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com25

Scala: Pattern matching, Concepts and Implementations

  • 1.
    SCALA PATTERN MATCHING, CONCEPTSAND IMPLEMENTATIONS Mustapha Michrafy PhD M. MICHRAFY & C. VALLIEZ Contact the authors : datascience.km@gmail.com datascience.km@gmail.com1 Cyril Valliez PhD - We thank Oussama Lachiri for helpful discussions.
  • 2.
    Context This study waspresented at the seminar « Data Science Principales, Tools and Applications » at Cermsem laboratory M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com2
  • 3.
    Goal This study aimsto present the pattern matching and its implementation with Scala M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com3
  • 4.
    Prerequisite Knowledge of • Scalaprogramming language • Functional programming notion M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com4
  • 5.
    Agenda 1. Basic patternmatching 2. Pattern matching and for loop 3. Pattern alternative: operator « | » 4. Pattern guards 5. Pattern guards and logical operator OR 6. Pattern matching and recursive function 7. Pattern matching on type 8. Pattern matching on tuple 9. Pattern matching on Option 10. Pattern matching on Immutable Collection 11. Pattern matching on Immutable Map 12. Pattern matching on Immutable Set 13. Pattern matching on List 14. Pattern matching on case class 15. Nested Pattern Matching in Case Classes 16. Matching on regular expression M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com5
  • 6.
    Basic pattern matching: switch-case def getChoicegetChoicegetChoicegetChoice(choicechoicechoicechoice: Int): String = choicechoicechoicechoice matchmatchmatchmatch { case 0 => "no" case 1 => "yes" case ____ => "error" } if choice = 0 then "no" else if choice = 1 then "yes" else then "error" Pattern matching getChoice(1) //> res0: String = yes getChoice(0) //> res1: String = no getChoice(3) //> res2: String = error Testing The wildcard pattern “_” matches any object whatsoever. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com6
  • 7.
    Pattern matching andinitialization val choicechoicechoicechoice = 0 var mesg ==== choicechoicechoicechoice match { case 0 => "no" case 1 => "yes" case _ => "error" } println(mesg) //> no We can use pattern matching for initializing a variable. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com7
  • 8.
    Pattern matching andfor loop val choiceschoiceschoiceschoices = List(0,1,10) for( choicechoicechoicechoice <- choices) { choice match { case 0 => println("no") case 1 => println("yes") case _ => println("error") } } //> no //> yes //>error We can use pattern matching with for loop M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com8
  • 9.
    Pattern alternative: operator« | » def getChoicegetChoicegetChoicegetChoice(choicechoicechoicechoice: Int): String = choicechoicechoicechoice matchmatchmatchmatch { casecasecasecase 0000 =>=>=>=> """"no"no"no"no" casecasecasecase 1111 => "no"=> "no"=> "no"=> "no" case 2 => "yes" case ____ => "error" } if choice in {0,1} then "no" else if choice = 2 then "oui" else then "error" Pattern matching « | » : OR With “|” , we can have multiple tests on a single line def getChoicegetChoicegetChoicegetChoice(choicechoicechoicechoice: Int): String = choicechoicechoicechoice matchmatchmatchmatch { casecasecasecase 0000 | 1 =>| 1 =>| 1 =>| 1 => """"no"no"no"no" case 2 => "yes" case ____ => "error" } getChoice(0) //>res1: String = no getChoice(1) //>res2: String = no Testing M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com9
  • 10.
    Pattern guards def sign(x:Double): Byte = x match { case x if x < 0if x < 0if x < 0if x < 0 => -1 case x if x > 0if x > 0if x > 0if x > 0 => 1 case _ => 0 } -1 if x < 0 sing(x) = 1 if x > 0 0 sinon Pattern matching sign(0) //> res1: Byte = 0 sign(2) //> res2: Byte = 1 sign(-2) //> res3: Byte = -1 Testing A pattern guard comes after a pattern and starts with an if. If a pattern guard is present, the match succeeds only if the guard evaluates to true M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com10
  • 11.
    Pattern guards andlogical operator OR def OR(p:Boolean, q: Boolean) : Boolean = (p, q)(p, q)(p, q)(p, q) match { case (x, y) if x==true | y==trueif x==true | y==trueif x==true | y==trueif x==true | y==true => true case _ => false } OR(false, false) //> res1: Boolean = false OR(false, true) //> res2: Boolean = true p q p OR q T T T T F T F T T F F F If (p=T | q=T) then OR(p,q)=true else OR(p,q) =false Testing Pattern matching Transform multiple parameters into one tuple (p,q) M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com11 1 1
  • 12.
    Pattern matching andrecursive function 1 if n = 0 n*(n-1)! otherwise n! ==== def factorialfactorialfactorialfactorial(n: Int): Int = n match { case 0 => 1 case _ => n*factorialfactorialfactorialfactorial(n-1) } def factorialfactorialfactorialfactorial(n:Int) : Int = { def fcfcfcfc(n:Int, p:Int) : Int = ((((n,pn,pn,pn,p)))) match { case (0,c) => c case (m,c) => fc(m-1,p*m) } fcfcfcfc(n,1) } factorial(0) //> res 1: Int = 1 factorial(4) //> res 2: Int = 24 1 Using a tuple (n,p) 2 Initialize an accumulator p to 1 Tail-recursive function M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com12
  • 13.
    Pattern matching ontype def matchByTypematchByTypematchByTypematchByType(z: Any): String = z match { case b:Boolean => s"A boolean : $b" case d:Double => s"A double : $d" case _ => " Unknown type " } 1 2 3 1 If z is Boolean type, b takes its value. 2 If z is the type Double , d takes its value. 3 Use wildcard when z is neither a Boolean type nor a Double type A typed pattern x:T consists of a pattern variable x and a type pattern T. The type of x is the type pattern T, where each type variable and wildcard is replaced by a fresh, unknown type. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com13
  • 14.
    Pattern matching ontuple def detectZeroInTupledetectZeroInTupledetectZeroInTupledetectZeroInTuple(x: Tuple2[Any,Any]):String = x match { case (0,0|(0,0)) => "Both values zero." case (0,b) => s"First value is 0 in (0,$b)" case (a, 0) => s"Second value is 0 in ($a, 0)" case _ => "Both nonzero : " + x } 1 The tuple pattern matches input in tuple form and enables the tuple to be decomposed into its constituent elements by using pattern matching variables for each position in the tuple. detectZeroInTuple((0,(0,0))) //> res1: String = Both values zero. detectZeroInTuple((0,0)) //> res2: String = Both values zero. detectZeroInTuple((0,11)) //> res3: String = First value is 0 in (0,11) 1 Match a first pattern if x=(0,0) or x=(0,(0,0)). M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com14
  • 15.
    Pattern matching onOption def getValueOptiongetValueOptiongetValueOptiongetValueOption[Any](x:Option[Any]) : String = x match{ case Some(x) => s"Some $x" case None => "None " } 1 Option -sealed abstract class- represents optional values. Instances of Option are either an instance of SomeSomeSomeSome or the object None.None.None.None. getValueOption(Option("hello")) //> Some hello getValueOption(Option(null)) //> None getValueOption(Option(())) //> Some () getValueOption(Option(List(10,11))) //Some List(10, 11)) 1 Match a Some(x) if x represents an existing value. Option Some None c c o 2 Match a None if x represents a non-existing value. 2 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com15
  • 16.
    Pattern matching onimmutable collection import scala.collection.immutable._ def getTypegetTypegetTypegetType(x:Traversable[Any]) : String = x match{ case s:Set[Any] => s"A Immutable Set : $s" case q:Seq[Any] => s"A Immutable Seq : $q" case _ => "A Immutable Map : $x" } getType(Set(0,2,4)) //> A Immutable Set : Set(0, 2, 4) getType(1 to 3) //> Immutable Seq : Range(1, 2, 3) getType(HashMap[Int,Int](1->13)) //> A Immutable Map : Map(1 -> 13) 2 Match a pattern then the type of x is returned Iterable Set Map Seq t t t t traversable t 1 1 2 3 3 Match wildcard then type map is returned This hierarchy is valid for mutable and immutable collections M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com16
  • 17.
    Pattern matching onImmutable Map import scala.collection.immutable._ def getTypeOfMapgetTypeOfMapgetTypeOfMapgetTypeOfMap(x:Map[Int,Int]) : String = x match{ case _:HashMap[Int,Int] => "A HashMap " case _:TreeMap[Int,Int] => "A TreeMap " case _ => "A ListMap " } getTypeOfMap(HashMap[Int,Int](1->12,2->10)) //>A HashMap getTypeOfMap(TreeMap[Int,Int](1->3,6->6)) //> A TreeMap getTypeOfMap(ListMap[Int,Int](1->13,6->16)) //> A ListMap 1 if x is neither a HashMap nor a TreeMap then x is a ListMap Map HashMap ListMap TreeMap t c c c This hierarchy is valid only for the immutable Map Map is a Trait and all (children) are implementation classes 1 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com17
  • 18.
    Pattern matching onimmutable Set import scala.collection.immutable._ import scala.collection.immutable.BitSet._ def getTypeOfSetgetTypeOfSetgetTypeOfSetgetTypeOfSet(x:Set[Int]) : String = x match{ case h:HashSet[Int] => "A HashSet " + (h.size,h.sum) case t:TreeSet[Int] => "A TreeSet " + (t.size,t.sum) case l:ListSet[Int] => "A ListSet " + (l.size,l.sum) case z:AnyRef => "type : " + z.getClass.getName } getTypeOfSet(new BitSet1(10)) //> type : scala.collection.immutable.BitSet$BitSet1 getTypeOfSet(HashSet(1,10,12)) //> A HashSet (3,23) getTypeOfSet(TreeSet(1,10)) //> A TreeSet (2,11) getTypeOfSet(ListSet(1,11,12)) //> A ListSet (3,24) Set HashSet ListSet BitSet t c c c This hierarchy is valid only for the immutable Set. The Set is a Trait. BitSet is an abstract class and all children are the class. TreeSet c SortedSet t The subclasses of the abstract class BitSet are BitSet1, BitSet2 and BitSetN M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com18
  • 19.
    Pattern matching onList 1/2 def sizeListsizeListsizeListsizeList[A](ls : List[A]) : Int = ls match{ case Nil => 0 case _::q => sizeList(q) + 1 } The following function computes the length of a list. It is based on two constructors NilNilNilNil and “::”. sizeList(List()) //> res40: Int = 0 sizeList(List(1)) //> res41: Int = 1 sizeList(List(1,(1,2),3,4)) //> res42: Int = 4 1 If the list is empty, Nil, then we return 0. 2 If ls represents a no-empty list then the length of list is (1+length(q)), where q represents the tail of the list. 1 2 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com19
  • 20.
    Pattern matching onList 2/2 def identifyListeidentifyListeidentifyListeidentifyListe(ls: List[Any]): String = ls match { case Nil => "empty list" case _::Nil => "list with single element" case _::_::Nil => "list has two elements" case _ => "list has at least tree elements" } All lists are built from two constructors : NilNilNilNil and “::”.... NilNilNilNil represents a empty list :::::::: builds a non empty list characterized by a head and a tail. identifyListe(Nil) //> empty list identifyListe(List((1,2))) //> list with single element identifyListe(List("Scala", 3)) //> list has two elements identifyListe(List(1,2,3)) //> list has at least tree elements M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com20
  • 21.
    Pattern matching oncase class case class PersonPersonPersonPerson(name: String, age: Int) def validateAgevalidateAgevalidateAgevalidateAge(p: Person): Option[String] = p match { case Person(name, age) if age > 18 => Some(s"Hi $name! age $age") case _ => None } Case classes are classes that get to String, hashCode, and equals methods automatically. It provide a recursive decomposition mechanism via pattern matching validateAge(Person("Alice", 19)) //> Some(Hi Alice! age 19) validateAge(Person("Bill", 15)) //> None 2 If the age is greater than18 , then we return the name and age of the person. 3 If the age of the person is less than 18 , then we return None. 2 3 1 1 We define a case class of a person with name and age. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com21
  • 22.
    Nested Pattern Matchingin Case Classes case class Address(street: String, city: String, country: String) case class Person(name: String, age: Int, address:Address) def checkPrscheckPrscheckPrscheckPrs(p: Person): Option[String] = p match { case Person(name, age, null) if age > 18 => Some(s"Hi $name! age $age") case Person(name, age, Address(_,_,ctr)) => Some(s"Hi $name! age $age $ctr") case _ => None } checkPrs(Person("Alice", 19,null)) //> Some(Hi Alice! age 19) checkPrs(Person("Bill", 15, Address("Scala Lane", "Chicago", "USA"))) //> Some(Hi Bill! age 15 USA) 2 If age > 18 & address = null, then we return the name and age of the person. 3 If the address != null then we return the name, age and the city of the person. 3 2 1 We define two case classes Address and Person. Person contains a subclass Address. 1 Case classes can contain other case classes, and the pattern matching can be nested. M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com22
  • 23.
    Matching on regularexpression val email = """(.*)@(.*).(.*)""".r val date = """(dddd)-(dd)-(dd)""".r def checkPattern(x:String) : Option[String] = x match{ case email(name,domain,extension) => Some(s"$name $domain $extension") case date(year, month, day) => Some(s"$year $month $day") case _ => None } A regular expression is used to determine whether a string matches a pattern and, if it does, to extract or transform the parts that match. Scala supports regular expressions through Regex class available in the scala.util.matching package. 2 3 1 4 1 We define a regular expressions for email and date by using the method rmethod rmethod rmethod r2 3 If regex of email is matched then extract name, domain and extension 4 If regex of date is matched then extract year, month and day checkPattern("info@scala.fr") //> Some(info scala fr) checkPattern("2016-03-26") //> Some(2016 03 26) M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com23
  • 24.
    References • Scala LanguageSpecification, http://www.scala- lang.org/files/archive/spec/2.11/ • Documentation for the Scala standard library, http://www.scala-lang.org/api/current/ • Beginning Scala, by Vishal Layka, David Pollak, 2015 • Programming in Scala, by Martin Odersky and al., 2011 • Programming Scala, by Dean Wampler, Alex Payne, 2014 M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com24
  • 25.
    Mustapha Michrafy PhD DataScientist and Expert Optim at ATOS Contact : datascience.km@gmail.com Cyril Valliez PhD Software Architect at Bouygues M. MICHRAFY & C. VALLIEZ datascience.km@gmail.com25