我正在进行尾递归的真正艰难时期......
我的当前函数从列表'l'
中过滤掉小于'n'的值var bytesPlainTextData = csp.Decrypt(bytesCypherText, true);
使用大型列表时,会导致堆栈溢出。
有人可以帮我理解如何将其转换为尾递归函数吗?
感谢您的任何意见!
答案 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)