Сопоставление списка с шаблоном, добавление фильтрации на основе объекта обращения

#scala #functional-programming #pattern-matching #tail-recursion

#scala #функциональное программирование #сопоставление с шаблоном #хвостовая рекурсия

Вопрос:

У меня есть список жителей мужского и женского пола, которые нужно повторить.

Как добавить фильтрацию по признаку пола в сопоставление шаблонов списков? (такой, который countOldManFloor возвращал бы 1, только если пол жителей равен Male , и в результате countOldManFloor(inhabitantsFemale) возвращал бы 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))
  

Онлайн-код

Я пытался case inhabitant: Male :: inhabitants if inhabitant.age > olderThen => 1 , = inhabitants.filter() match {} но это не сработало

Комментарии:

1. Привет @techkuz, вы хотите проверять постепенно Gender age или оба? Я этого не понимаю.

2. Привет @Chema. Оба, мне нужно вычислять только мужчин с фильтрацией по возрасту

3. Привет @techkuz, так что результатом будет счетчик мужчин старше 30 лет, если я не ошибаюсь.

Ответ №1:

Вы можете сопоставлять шаблоны внутри шаблонов. В этом случае Male шаблон внутри Inhabitant() шаблона внутри :: шаблона 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
  

Обратите внимание, что я сделал olderThan переданный параметр. Методы, которые ссылаются на переменные за пределами их пространства определения, — это запах кода.

Ответ №2:

Я понимаю, что вам нужен счетчик мужчин старше 30 лет, поэтому я добавил проверку на гендерное условие.

   def countOldManFloor(inhabitants: List[Inhabitant]): Int = {
    def checkGender(inhabitant: Gender): Boolean = inhabitant match {
      case Male => true
      case _ => false
    }

    @tailrec
    def loop(lst: List[Inhabitant], cont: Int): Int = {
      lst match {
        case Nil => cont
        case (h :: tail) if h.age > olderThen amp;amp; checkGender(h.gender) => loop(tail, cont   1)
        case _ => loop(lst.tail, cont)
      }
    }
    loop(inhabitants, 0)
  }
  

Ответ №3:

Ваш метод не работает, потому что вы ничего не добавляете, могут быть возвращены только 1 и 0. Если вы не заботитесь о хвостовой рекурсии, это может сработать:

 def countOldManFloor(inhabitants: List[Inhabitant]): Int = inhabitants match {
  case Inhabitant(age, Male) :: inhabitants if age > olderThan => countOldManFloor(inhabitants)   1
  case inhabitant :: inhabitants => countOldManFloor(inhabitants)
  case Nil => 0
}
  

Scastie

Я думаю, вы можете сделать это просто count вместо любой рекурсии, хотя:

 def countOldManFloor(inhabitants: List[Inhabitant]): Int = 
  inhabitants.count(inhabitant => inhabitant.age > olderThan amp;amp; inhabitant.gender == Male)
  

Scastie