[英]How to make this code more functional?
我是函数式编程的新手。 我刚尝试解决以下问题:
[ 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循环和两个可变变量,并使这段代码更具功能性。
任何帮助将不胜感激。
谢谢。 :)
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
。
这个尾递归函数删除你的两个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))
}
}
Rahul,正如我所说,Scala中没有一个unfold
功能。 Scalaz中有一个,所以我将使用那个显示解决方案。 下面的解决方案只是调整Patrick的 答案 ,使用展开而不是递归。
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))
}
}
我认为这是解决问题的相当昂贵的方法,但非常直观的一个恕我直言:
scala> Stream.iterate(255)(_ / 10).takeWhile(_ > 0).map(_ % 10).reverse
res6: scala.collection.immutable.Stream[Int] = Stream(2, 5, 5)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.