Расширяя ответ @ Scalway, следующим логическим шагом может быть оптимизация рекурсивной функции до хвостовой рекурсии . Рекурсивная функция может быстро создавать кадры стека, которые приводят к StackOverflowError
, но компилятор Scala может оптимизировать хвостовую рекурсивную функцию для использования только одного кадра стека.
def filter(list: List[Int], cond: Int => Boolean): List[Int] = {
@scala.annotation.tailrec
def loop(pending: List[Int], cumulated: List[Int]): List[Int] = pending match {
case Nil =>
cumulated
case head :: tail =>
loop(tail, if (cond(head)) head :: cumulated else cumulated)
}
loop(list, Nil).reverse
}
В случае не очевидно, как хвостовая рекурсия стала возможной, приведенная выше ссылка подробно описывает общую схему использования accumulator
в качестве дополнительного аргумента функции для достижения хвостовой рекурсии.
Поскольку filtering
это обычное преобразование, применимое почти ко всем коллекциям, и для того, чтобы функция взяла список generi c type , я включаю также обобщенный фрагмент:
def filter[T](list: List[T], cond: T => Boolean): List[T] = {
@scala.annotation.tailrec
def loop(pending: List[T], cumulated: List[T]): List[T] = pending match {
case Nil =>
cumulated
case head :: tail =>
loop(tail, if (cond(head)) head :: cumulated else cumulated)
}
loop(list, Nil).reverse
}
Тестирование:
filter[Int](List(1, 2, 3, 4, 5), _ != 3)
// res1: List[Int] = List(1, 2, 4, 5)
filter[String](List("apple", "pear", "orange"), _ contains "r")
// res2: List[String] = List("pear", "orange")