#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
}
Я думаю, вы можете сделать это просто count
вместо любой рекурсии, хотя:
def countOldManFloor(inhabitants: List[Inhabitant]): Int =
inhabitants.count(inhabitant => inhabitant.age > olderThan amp;amp; inhabitant.gender == Male)