Lunch Scala Kata: Perfect Numbers

Today I met up with Tim Dalton to do some pair programming on a scala kata… partial because I wanted to exercise both my scala and pair programming skills, partially because I wanted to steal some of Tim’s expertise to help me learn scala better. Since lunches are usually crammed and I expected us to be pressed for time, I selected a simple code kata: finding perfect numbers.

So to start, I wrote the first example, 5 is not a perfect number:

object PerfectNumbersSpec extends Specification{
  "Perfect Numbers" should{
    "5 is not a perfect number" in {
      IsPerfectNumber(5) must be(false)
    }
  }
}

Following the rule of doing the simplest thing to make it pass, we just returned false:

object IsPerfectNumber extends (Int => Boolean) {
  def apply(n:Int) = false
}

Next we wrote an example of 6 being identified as a perfect number, in which I just returned n % 2 ==0. Since this felt like cheating, the next step was an example of numbers that are not perfect numbers in the range of 1 to 10:

   "if its not a perfect number should return false" in {
      (1 to 10).filter(_ != 6).foreach(n =>
        IsPerfectNumber(n) must be(false)
      )
    }

My cheat of returning n mod 2 no longer worked, so I did the first thing that came to mind:

object IsPerfectNumber extends (Int => Boolean) {
  def apply(n:Int) = {
    if(n % 2 == 0) (1 to n / 2).foldLeft(0)(_+_) == n else false
  }
}

All examples passed, so I took my turn to writing the next example:

"28 is a perfect number" in {
      IsPerfectNumber(28) must be(true)
    }

to which Tim showed off his scala skills by converting my previous code to the following:

object IsPerfectNumber extends (Int => Boolean) {
  def apply(n:Int) = {
    (1 to n / 2).filter (n % _ == 0).foldLeft(0)(_+_) == n
  }
}

For the scala impaired, that creates a range of numbers of one to n divided by two, filters it out to find only the divisors, then calls foldLeft which adds all of the divisors together. The example passed, so we added a couple more checks to be sure and it all went well. Here’s the specification in it’s entirety:

import org.specs._

object PerfectNumbersSpec extends Specification{
  "Perfect Numbers" should{
    "5 is not a perfect number" in {
      IsPerfectNumber(5) must be(false)
    }
    "6 is a perfect number" in {
      IsPerfectNumber(6) must be(true)
    }
    "28 is a perfect number" in {
      IsPerfectNumber(28) must be(true)
    }
    "496 is a perfect number" in {
      IsPerfectNumber(496) must be(true)
    }

    "8128 is a perfect number" in {
      IsPerfectNumber(8128) must be(true)
    }
    "if its not a perfect number should return false" in {
      (1 to 500).filter(!List(6,28,496).contains(_)).foreach(n =>
        IsPerfectNumber(n) must be(false)
      )
    }
  }
}

It was definitely a fun experience and we finished the kata fairly quickly (I think 20 minutes or so). I’m planning to do a few more scala kata lunches! :)

You can leave a response, or trackback from your own site.

Facebook comments:

3 Responses to “Lunch Scala Kata: Perfect Numbers”

  1. I love the simplicity of the code. Thanks for this great sample.

  2. Tony Morris says:

    Hi James,
    Since Scala 2.8, then the expression .foldLeft(0)(_+_) can be reduced to .sum.

    If you are using Scalaz, then you can use ∑ (which I prefer).

  3. James Carr says:

    Thanks Tony. I downloaded scalaz last week but have not folled around with it yet. Hopefully I’ll have a chance to this week. :)

Leave a Reply

Subscribe to RSS Feed Follow me on Twitter!