使用尾递归过滤列表

时间:2016-10-03 23:14:25

标签: scala tail-recursion

我正在进行尾递归的真正艰难时期......

我的当前函数从列表'l'

中过滤掉小于'n'的值
var bytesPlainTextData = csp.Decrypt(bytesCypherText, true);

使用大型列表时,会导致堆栈溢出。

有人可以帮我理解如何将其转换为尾递归函数吗?

感谢您的任何意见!

2 个答案:

答案 0 :(得分:3)

通常使用辅助函数来累积结果。 filterR有一个额外的参数acc,我们会将值大于n添加到。{/ p>

def filter(n: Int, l: List[Int]): List[Int] = {
  @scala.annotation.tailrec
  def filterR(n: Int, l: List[Int], acc: List[Int]): List[Int] =  l match {
    case Nil => acc
    case hd :: tl if(hd < n) => filterR(n, tl, acc)
    case hd :: tl            => filterR(n, tl, hd :: acc)
  }
  filterR(n, l, List[Int]())
} 

根据@jwvh的建议:

@scala.annotation.tailrec
def filter(n: Int, l: List[Int], acc: List[Int] = List[Int]()): List[Int] =  l match {
   case Nil => acc.reverse
   case hd :: tl if(hd < n) => filter(n, tl, acc)
   case hd :: tl            => filter(n, tl, hd :: acc)
} 

答案 1 :(得分:2)

@ Brian的答案很好,但它反转了输入列表。这通常不是预期的行为。

@jwvh的建议是将第三个参数中的累加器传递给函数,但是将私有API泄露给公共API。

在返回答案之前,任何一种解决方案都需要反转累加器 - 有效地通过输入列表两次 进行迭代。这是一个疯狂的实现,特别是考虑到你试图实现这个以促进大型列表。

考虑这种尾递归实现,它不会公开私有API,也不需要在过滤后反转累加器。

  

免责声明:这是我写过的第一个scala程序。欢迎对任何实施方式或细节进行反馈。

def filter(n: Int, xs: List[Int]): List[Int] = {
  @scala.annotation.tailrec
  def aux(k: List[Int] => List[Int], xs: List[Int]): List[Int] = xs match {
    case Nil => k(Nil)
    case x :: xs if (x < n) => aux(k, xs)
    case x :: xs            => aux((rest: List[Int]) => k(x :: rest), xs)
  }
  aux(identity, xs)
}

filter(5, List(1,2,3,4,5,6,7,8,9,0)))
// => List(5, 6, 7, 8, 9)