繁体   English   中英

如何使这段代码更实用?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM