Scala でとことん FizzBuzz する(その 4)
最初にお詫び。前回の記事にかなり大幅な修正を加えています。再度確認をしていただけるとありがたいです。
追記 : 今回作ったソースファイル群(+ テストコード)を GitHub で公開しました。
akaneko3/FizzBuzzScala · GitHub
分岐アルゴリズム再考(続き)
その 3 : Map
を利用する
Ruby の Hash
を利用して作られたものにヒントを得て作ったもの。
package jp.mydns.akanekodou.scala.fizzbuzz class ApplicatorFizzBuzz extends FizzBuzz { private val applicators = Map(3 -> "Fizz", 5 -> "Buzz") def toFizzBuzz(n : Int) : String = { applicators.filterKeys(n % _ == 0).values.mkString } val fb = Stream.from(1).map(toFizzBuzz) }
Map
を利用するとこんな書き方も出来る。条件分岐の部分がだいぶすっきりしている。拡張にも強く、
private val applicators = Map(3 -> "Fizz", 5 -> "Buzz", 7 -> "Woof")
とすれば FizzBuzzWoof になる。
(Main.scala
は省略)
その 4 : toFizzBuzz
を使わない
Haskell で同様のものが作られていて、それにヒントを得たもの。
package jp.mydns.akanekodou.scala.fizzbuzz import jp.mydns.akanekodou.scala.collection.util.StreamUtils._ class StreamZipFizzBuzz extends FizzBuzz { private val f = List.fill(2)("") :+ "Fizz" private val b = List.fill(4)("") :+ "Buzz" val fb = (f.cycle zip b.cycle).map(t => t._1 + t._2) }
package jp.mydns.akanekodou.scala.collection.util object StreamUtils { implicit class iterableCycle [A] (self : Iterable[A]) { def cycle : Stream[A] = Stream.continually(self).flatten } }
究極の禁じ手かも(苦笑)。暗黙クラスを利用してあたかも Iterable
を継承するクラスのインスタンスに cycle
メソッドがあるかのように振る舞わせ、
"", "", "Fizz", "", "", "Fizz", "", "", "Fizz", "", "", "Fizz", "", "", "Fizz", ...
という Stream[String]
と
"", "", "", "", "Buzz", "", "", "", "", "Buzz", "", "", "", "", "Buzz", ...
という Stream[String]
を作ってそれを zip
すると
("", ""), ("", ""), ("Fizz", ""), ("", ""), ("", "Buzz"), ("Fizz", ""), ("", ""), ("", ""), ("Fizz", ""), ("", "Buzz"), ("", ""), ("Fizz", ""), ("", ""), ("", ""), ("Fizz", "Buzz"), ...
という Stream[(String, String)]
が出来上がる。後は各 Tuple
を文字列結合でつなげることで目的の Stream[String]
を条件文を一切使わずに生成することに成功した。
(Main.scala
は省略)