我是函数式编程的新手。我刚试过解决以下问题:
[ a rough specification ]
e.g.1:
dividend : {3,5,9}
divisor : {2,2}
radix = 10
ans (remainder) : {7}
Procedure :
dividend = 3*10^2+5*10^1+9*10^0 = 359
similarly, divisor = 22
so 359 % 22 = 7
e.g.2:
dividend : {555,555,555,555,555,555,555,555,555,555}
divisor: {112,112,112,112,112,112,112,112,112,112}
radix = 1000
ans (remainder) : {107,107,107,107,107,107,107,107,107,107}
我对此问题的解决方案是:
object Tornedo {
def main(args: Array[String]) {
val radix: BigInt = 1000
def buildNum(segs: BigInt*) = (BigInt(0) /: segs.toList) { _ * radix + _ }
val dividend = buildNum(555,555,555,555,555,555,555,555,555,555)
val divisor = buildNum(112,112,112,112,112,112,112,112,112,112)
var remainder = dividend % divisor
var rem = List[BigInt]()
while(remainder > 0) {
rem = (remainder % radix) :: rem
remainder /= radix
}
println(rem)
}
}
虽然我对这段代码非常满意,但我想知道如何消除while循环和放大器。两个可变变量,使这个代码更具功能性。
非常感谢任何帮助。
感谢。 :)
答案 0 :(得分:3)
Scala 2.8中的尾递归解决方案:
def reradix(value: BigInt, radix: BigInt, digits:List[BigInt] = Nil): List[BigInt] = {
if (remainder==0) digits
else reradix(value/radix ,radix ,(value % radix) :: digits)
}
这个想法通常是将一段时间转换为一个递归解决方案,在那里你可以跟踪你的解决方案(所以它可以是尾递归,就像它在这里一样)。如果您改为使用
(value % radix) :: reradix(value/radix, radix)
你也会计算解决方案,但它不会是尾递归的,所以部分答案会被推到堆栈上。使用默认参数,添加一个允许存储累积答案并使用尾递归的最终参数在语法上很好,因为您可以调用reradix(remainder,radix)
并免费传递Nil
。
答案 1 :(得分:3)
这个尾递归函数删除你的两个mutable var和循环:
object Tornedo {
def main(args: Array[String]) {
val radix: BigInt = 1000
def buildNum(segs: BigInt*) = (BigInt(0) /: segs.toList) { _ * radix + _ }
val dividend = buildNum(555,555,555,555,555,555,555,555,555,555)
val divisor = buildNum(112,112,112,112,112,112,112,112,112,112)
def breakup(n: BigInt, segs: List[BigInt]): List[BigInt] =
if (n == 0) segs else breakup(n / radix, n % radix :: segs)
println(breakup(dividend % divisor, Nil))
}
}
答案 2 :(得分:3)
Rahul,正如我所说,在Scala中不是 unfold
函数。 Scalaz中有一个,所以我将使用那个显示解决方案。下面的解决方案只是调整Patrick's answer来使用展开而不是递归。
import scalaz.Scalaz._
object Tornedo {
def main(args: Array[String]) {
val radix: BigInt = 1000
def buildNum(segs: BigInt*) = (BigInt(0) /: segs.toList) { _ * radix + _ }
val dividend = buildNum(555,555,555,555,555,555,555,555,555,555)
val divisor = buildNum(112,112,112,112,112,112,112,112,112,112)
val unfoldingFunction = (n: BigInt) =>
if (n == 0) None else Some((n % radix, n / radix))
println((dividend % divisor).unfold[List, BigInt](unfoldingFunction))
}
}
答案 3 :(得分:2)
我认为这是解决问题的相当昂贵的方法,但非常直观的恕我直言:
scala> Stream.iterate(255)(_ / 10).takeWhile(_ > 0).map(_ % 10).reverse
res6: scala.collection.immutable.Stream[Int] = Stream(2, 5, 5)