Wednesday, January 4, 2012

Scala Divisibility

So I was looking for some simple yet interesting problems to solve that would help me explore the power of Scala. That lead me to ProjectEuler.net. I would highly recommend this site to anyone interested in puzzle solving. The problem I started with was as follows:

"What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?"

The problem is simple enough, but I the goal was to solve the problem in a "Functional" way so as to utilize the power of Scala. So no loops!

Following is the final code listing that solves this problem without using any loops. Also, I tried to avoid any "var"iables but some "val"use are used for efficiency. But then that is the power of Scala to combine functional with non-functional code!


import scala.collection.mutable.HashMap

object Divisibility {
  val range = 2 to 20 // Range of numbers we are working on
  val primes = range.filter(prime(_)) // Prime numbers in the range

  // Test for prime number (Note: can be faster if tested until sqrt(n) instead of n/2
  def prime(n:Int): Boolean = n match {
    case 1 => false
    case _ => !(2 to scala.math.ceil(n/2).toInt).exists( n % _ == 0)
  }
  
  // Function that returns a list of prime factors of a given integer
  def factorize(n:Int): List[Int] = primes.find(n%_==0) match {
    case Some(p) => p::factorize(n/p)
    case None => Nil
  }
  
  // Function that returns the powers of prime factors of a number
  def factorCount(n:Int): List[Int] = {
    val factors = factorize(n)
    return primes.map(p => factors.count(_==p)).toList
  }
  
  // Element-wise maximum list for two lists
  def listMax(l1:List[Int], l2:List[Int]): List[Int] = (l1 zip l2).map(x => scala.math.max(x._1,x._2))
  
  // Main function to calculate the required value "v"
  def main(args: Array[String]): Unit = {
    val maxFactors = (range.map(factorCount(_))).reduce(listMax(_,_))
    val v = (primes zip maxFactors).map(x => scala.math.pow(x._1,x._2).toInt).reduce(_*_)
    
    println(v)
  }
}



No comments:

Post a Comment