Thursday, May 5, 2011

01 Kata [scala] - sum of multiples of 3 or 5 less than 1000

Now, lets take a look at the scala solution.

class FirstKata {
  def sum: Int = {
    var sum = 0;

    for (i <- 1 until 1000) {
      if (i % 3 == 0 || i % 5 == 0)
        sum = sum + i
    }

    sum
  }
}

class FirstKataTest extends Assertions {
  @Test
  def sum() {
    val kata = new FirstKata

    assertEquals(kata.sum, 233168)
  }
}

This solution is very similar to the java one except for the fact that was written in scala.
Lets perform a serie of little refactoring in order to get the more generic solution we are capable of.

class FirstKata {
  def sum(upperLimit: Int): Int = {
    var sum: Int = 0;

    for (i <- 1 until upperLimit) {
      if (i % 3 == 0 || i % 5 == 0)
        sum = sum + i
    }

    sum
  }
}

class FirstKataTest extends Assertions {
  @Test
  def sum() {
    val kata = new FirstKata

    assertEquals(kata sum 10, 23)
    assertEquals(kata sum 1000, 233168)
  }
}

The first refactoring added the upperLimit parameter.

class FirstKata {
  def sum(upperLimit: Int, multiples: Seq[Int]): Int = {
    var sum: Int = 0;

    for (i <- 1 until upperLimit) {
      if (isMultiple(i, multiples))
        sum = sum + i
    }

    sum
  }

  def isMultiple(upperLimit: Int, multiples: Seq[Int]): Boolean = {
    for (multiple <- multiples) {
      if (upperLimit % multiple == 0)
        return true
    }

    return false
  }
}

class FirstKataTest extends Assertions {
  @Test
  def sum() {
    val kata = new FirstKata

    assertEquals(kata.sum(10, 3::5::Nil), 23)
    assertEquals(kata.sum(1000, 3::5::Nil), 233168)
  }
}

The second refactoring add the multiples parameter as a Seq[Int].

class FirstKata {
  def sum(upperLimit: Int, multiples: Seq[Int]): Int = {
    var sum: Int = 0;

    for (i <- 1 until upperLimit if isMultiple(i, multiples))
    yield sum = sum + i

    sum
  }

  def isMultiple(upperLimit: Int, multiples: Seq[Int]): Boolean = {
    if (multiples.filter(upperLimit % _ == 0).isEmpty) 
      false 
    else 
      true
  }
}

In this refactoring we made use of for comprehension to get a more concise solution

class FirstKata {
  def sum(upperLimit: Int, mult: Seq[Int]): Int = upperLimit match {
    case 0 => 0
    case x =>
      if (isMultiple(x, mult))
        (x + sum((x - 1), mult))
      else
        sum((x - 1), mult)
  }

  def isMultiple(upperLimit: Int, multiples: Seq[Int]): Boolean = {
    if (multiples.filter(upperLimit % _ == 0).isEmpty)
      false 
    else 
      true
  }
}

Now using pattern matching. It illustrates the what one can get using FP.
And at last but not least.

class FirstKata {
  def sum(upperLimit: Int, multiples: Seq[Int]): Int = {
    List.range(1, upperLimit)
       .filter(isMultiple(_, multiples)).foldLeft(0)(_ + _)
  }

  def isMultiple(upperLimit: Int, multiples: Seq[Int]): Boolean = {
    if (multiples.filter(upperLimit % _ == 0).isEmpty)
      false 
    else 
      true
  }
}

A more concise solution.

No comments:

Post a Comment