Fizz Buzz 再び

ScalaでFizz Buzz - 不悔必省

からトラックバックを頂いたこともあり、
改めてFizz Buzzを書いてみた・・・


シンプル版
これは上記リンク先のとほとんど同じだが、この場合"n match"の部分は省略できる。

(1 to 100).map {
  case n if (n%3 == 0) && (n%5 == 0) => "Fizz Buzz"
  case n if (n%3 == 0) => "Fizz"
  case n if (n%5 == 0) => "Buzz"
  case n => n.toString
}

同じことを、for内包表記で書けば

for (n <- 1 to 100) yield n match {
  case n if (n%3 == 0) && (n%5 == 0) => "Fizz Buzz"
  case n if (n%3 == 0) => "Fizz"
  case n if (n%5 == 0) => "Buzz"
  case n => n.toString
}

これは、内部的にも上と全く同じ

ちょっと改良して、DRYな感じにしてみた。

(1 to 100).map{ n =>
  val b = new scala.collection.mutable.ArrayBuffer[String]
  if (n%3 == 0) b + "Fizz"
  if (n%5 == 0) b + "Buzz"
  if (b.isEmpty) n.toString else b.mkString(" ")
}


ここで、ふと思い・・・

(1 to 100).map {n =>
  val m3 = n % 3 == 0
  val m5 = n % 5 == 0
  n match {
    case n if (m3 && m5) => "Fizz Buzz"
    case n if (m3)       => "Fizz"
    case n if (m5)       => "Buzz"
    case n => n.toString
  }
}

for {
  n <- 1 to 100
  m3 = n % 3 == 0
  m5 = n % 5 == 0
} yield n match {
  case n if (m3 && m5) => "Fizz Buzz"
  case n if (m3)       => "Fizz"
  case n if (m5)       => "Buzz"
  case n => n.toString
}

を比較してみた。

Xprint:namerオプションをつかって確認したところ、
for内包表記バージョンは、内部的には以下と同じ模様。
mapが2回入っているので効率が悪い。

(1 to 100).map{n =>
  val m3 = n % 3 == 0
  val m5 = n % 5 == 0
 (n, m3, m5)
}.map{
 case (n, m3, m5) => n match {
  case n if (m3 && m5) => "Fizz Buzz"
  case n if (m3)       => "Fizz"
  case n if (m5)       => "Buzz"
  case n => n.toString
 }
}