Hatena::Groupocaml-nagoya

yoshihiro503の関数的日記

2011-11-03 (Thu)

社内プログラミングコンテスト - Excel列名変換問題 - をScalaで解いてみた

| 12:14 | 社内プログラミングコンテスト - Excel列名変換問題 - をScalaで解いてみた - yoshihiro503の関数的日記 を含むブックマーク はてなブックマーク - 社内プログラミングコンテスト - Excel列名変換問題 - をScalaで解いてみた - yoshihiro503の関数的日記

Scala練習中なので、Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編) - give IT a try の問題をScalaを使って解いてみた。

ディレクトリ構成はこんな感じ。

src/
 |- main/scala/Main.scala
 `- test/scala/Test.scala

まず、ブログ記事にあったperlでのテストコードを元にScalaTestを使ったScalaテストコードを用意した。

ブログ記事にはto_nのテストしか無かったが、of_nも同様に付け足した。テストファースト大事

import org.scalatest.FunSuite
import Main._

class Test extends FunSuite {
  test("to_n") {
    assert(to_n("A") === 1)
    assert(to_n("B") === 2)
    assert(to_n("C") === 3)
    assert(to_n("Y") === 25)
    assert(to_n("Z") === 26)
    assert(to_n("AA") === 27)
    assert(to_n("AB") === 28)
    assert(to_n("AY") === 51)
    assert(to_n("AZ") === 52)
    assert(to_n("BA") === 53)
    assert(to_n("BB") === 54)
    assert(to_n("IV") === 256)
    assert(to_n("XFD") === 16384)
  }

  test("of_n") {
    assert("A" === of_n(1))
    assert("B" === of_n(2))
    assert("C" === of_n(3))
    assert("Y" === of_n(25))
    assert("Z" === of_n(26))
    assert("AA" === of_n(27))
    assert("AB" === of_n(28))
    assert("AY" === of_n(51))
    assert("AZ" === of_n(52))
    assert("BA" === of_n(53))
    assert("BB" === of_n(54))
    assert("IV" === of_n(256))
    assert("XFD" === of_n(16384))
  }
}

実装はこんな感じ。Haskellならもっと簡潔にかけるかも。

object Main {
  def main(args : Array[String]) = {
    val mode = args(0).toInt
    val input = args(1)
    mode match {
      case 0 =>
        println(to_n(input))
      case 1 =>
        println(of_n(input.toInt))
    }
  }

  def to_n(input : String) : Int = {
    def alp_to_n(alp : Char) = (alp.toInt - 'A'.toInt + 1)
    input.map(alp_to_n).foldLeft(0) {
      case (store, n) => store * 26 + n
    }
  }

  def of_n(input : Int) = {
    def n_to_alp(n : Int) = ('A' + n - 1).toChar
    def iter(x : Int) : List[Int] =
      (x%26, x/26) match {
        case (0, 0) => Nil
        case (0, r) => 26 :: iter(r-1)
        case (a, r) => a :: iter(r)
      }
    iter(input).map(n_to_alp).reverse.mkString
  }
}

HinesHines2011/12/11 21:32Real brain power on display. Thanks for that anwser!