After practicing the Prime Factors Kata in Ruby a couple of days, I tried the same exercise in Scala.
Except the fact that practicing Katas is a wonderful tool to learn your IDE and
optimize your workflow, I think Katas are also great to learn programming languages.
You just don't have to think about your programming-problem, you can just think about your language.
Its been a while since I played around with Scala, so i started my daily Kata in Scala to refresh my skills.
The fact that Scala is not just an object oriented language but also a functional language, led me to a complete different solution of the prime factors kata as in Java or Ruby. I took the immutable List of Scala instead of a mutable Array, so I had to build the algorithm in a recursive manner.
Ok, enough talk. Here is my first solution:
// PrimeFactorsTest.scala import org.junit.Test; import org.junit.Assert._; import org.hamcrest.CoreMatchers._; class PrimeFactorsTest { @Test def shouldFactorNumbers = { Map( 1 -> Nil, 2 -> List(2), 3 -> List(3), 4 -> List(2,2), 5 -> List(5), 6 -> List(2,3), 7 -> List(7), 8 -> List(2,2,2), 9 -> List(3,3), 10 -> List(2,5), (2*2*5*7*13) -> List(2,2,5,7,13) ).foreach{ case (n, factors) => assertThat(PrimeFactors.of(n), is(equalTo(factors))) } } }
// PrimeFactors.scala object PrimeFactors { def of(n:Int) : List[Int] = tryFactor(2, n) private def tryFactor(divider: Int, n: Int) : List[Int] = if (n > 1) takeIfFactorElseTryNext(divider, n) else Nil private def takeIfFactorElseTryNext(divider: Int, n: Int) : List[Int] = if (n % divider == 0) divider :: takeIfFactorElseTryNext(divider, n/divider) else tryFactor(divider+1, n) }
EDIT:
A few days later, I came to a slightly better solution.
I now use a nested function tryFactor to do the recursion. It's nested
because in a different context it makes absolutly no sense.
As in my first solution I used object instead of class to create the singleton object PrimeFactors. Again it is not written in tail-recursive style, but Scala obviously optimizes it.
// PrimeFactors.scala object PrimeFactors { def of(n:Int) = { def tryFactor(n:Int, divider:Int) : List[Int] = if (n == 1) Nil else if (n % divider == 0) divider :: tryFactor(n/divider, divider) else tryFactor(n, divider+1) tryFactor(n, 2) } }
No comments:
Post a Comment