Search code examples
scalafunctional-programmingpattern-matchingtail-recursion

List pattern matching add filtering based on case object


I have a list of Male and Female inhabitants to be iterated over.

How to add filtering based on gender to the list pattern matching? (such that countOldManFloor would return 1 only if inhabitants gender is Male and as a result countOldManFloor(inhabitantsFemale) would return 0)

import scala.annotation.tailrec

trait Gender

case object Female extends Gender

case object Male extends Gender

case class Inhabitant(age: Int= 50, gender: Gender)

val olderThen = 30

val inhabitantsBoth: List[Inhabitant] = List(Inhabitant(gender=Male), Inhabitant(gender=Female))
val inhabitantsFemale: List[Inhabitant] = List(Inhabitant(gender=Female), Inhabitant(gender=Female))
val inhabitantsMale: List[Inhabitant] = List(Inhabitant(gender=Male), Inhabitant(gender=Male))


@tailrec
def countOldManFloor(inhabitants: List[Inhabitant]): Int = inhabitants match {
  case inhabitant :: inhabitants  if inhabitant.age > olderThen => 1
  case inhabitant :: inhabitants => countOldManFloor(inhabitants)
  case Nil => 0
}


println(countOldManFloor(inhabitantsBoth))
println(countOldManFloor(inhabitantsMale))
println(countOldManFloor(inhabitantsFemale))

Online code

I tried case inhabitant: Male :: inhabitants if inhabitant.age > olderThen => 1 and = inhabitants.filter() match {} but it did not work


Solution

  • You can match patterns within patterns. In this case the Male pattern, within the Inhabitant() pattern, within the :: pattern of a List.

    @tailrec
    def countOldManFloor(inhabitants : List[Inhabitant]
                        ,ageLimit    : Int
                        ,acc         : Int = 0): Int = inhabitants match {
      case Inhabitant(age,Male) :: tl if age > ageLimit => 
                      countOldManFloor(tl, ageLimit, acc + 1)
      case _ :: tl => countOldManFloor(tl, ageLimit, acc)
      case Nil     => acc
    }
    
    countOldManFloor(inhabitantsBoth, olderThan)    // 1
    countOldManFloor(inhabitantsMale, olderThan)    // 2
    countOldManFloor(inhabitantsFemale, olderThan)  // 0
    

    Notice that I made olderThan a passed parameter. Methods that reference variables outside of their definition space is a code smell.