代码之家  ›  专栏  ›  技术社区  ›  missingfaktor Kevin Wright

如何使此代码更具功能性?

  •  2
  • missingfaktor Kevin Wright  · 技术社区  · 16 年前

    我是函数式编程的新手。我只是尝试解决以下问题:

    [ 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循环&两个可变变量,使此代码更具功能性。

    任何帮助都将不胜感激。

    4 回复  |  直到 16 年前
        1
  •  3
  •   Patrick    16 年前

    此尾部递归函数删除两个可变变量和循环:

    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
  •   Daniel C. Sobral    16 年前

    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 免费入场。

        3
  •  3
  •   Community Mohan Dere    9 年前

    拉胡尔,就像我说的,在那里 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))
      }
    }
    
        4
  •  2
  •   Alexey    16 年前

    我认为这是一种非常昂贵的解决问题的方法,但非常直观:

    scala> Stream.iterate(255)(_ / 10).takeWhile(_ > 0).map(_ % 10).reverse
    res6: scala.collection.immutable.Stream[Int] = Stream(2, 5, 5)