【Scala入門】 ScalaでFizzBuzz問題を解く
Apache Sparkの学習の一環としてScalaに触れてみることにしました。
本記事では、Scalaの基本的な構文を確認した後にFizzBuzz問題を解いていきます。
SparkとScalaの関係性について詳しく知りたい方はこちら
hktech.hatenablog.com
FizzBuzz問題とは
FizzBuzz問題とは1から100までの数字について、3で割り切れる場合に”Fizz”、5で割り切れる場合に”Buzz”、両者で割り切れる場合に”FizzBuzz”、それ以外の場合はその数字を出力させるプログラミング問題です。
調べてみたらもともとは英語圏で遊ばれている言葉遊びらしいです。
プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。ただし、3で割り切れる場合は「Fizz」(Bizz Buzzの場合は「Bizz」)、5で割り切れる場合は「Buzz」、両者で割り切れる場合(すなわち15で割り切れる場合)は「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。
いや、ただの宴会ゲーム。難しそう。
Scalaのプログラミング構文
いきなりScalaの実装に入る前に、基本的なプログラミング構文を確認しておきます。
FizzBuzz問題で必要となるのは大きく3つです。
- 1から100までの数字のリスト(配列)
- リストをまわすためのfor文
- 条件分岐するためのif-else文
リスト
まずはリストの構文について確認していきます。
1から3までのリストを作ります。
$ List(1, 2, 3) res: List[Int] = List(3, 1, 4)
直感的ですね。てかScalaって型推論あるのか、、、確かに型宣言はしてないですよね。
次に1から100のリストを作ります。さすがに1から100まですべて書き出すわけにはいかないですよね。
そこで、Rangeというものを使います。これはPythonと同じですね。
$ Range(1, 101) res: scala.collection.immutable.Range = Range 1 until 101
できてそうですね。これをリスト型にします。
$ Range(1, 101).toList res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)
こんな書き方もできます。
$ (1 to 100).toList res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)
ScalaでFizzBuzz問題を解く
FizzBuzz問題に必要なScalaプログラミング構文を完全に理解したところで、早速実装をしてみました。
for (s <- (1 to 100)) if (s % 15 == 0) println("FizzBuzz") else if (s % 3 == 0) println("Fizz") else if (s % 5 == 0) println("Buzz") else println(s)
無事にFizzBuzz問題が解けました!
コーディング面接でFizzBuzzを書く機会があれば間違いなくScalaで書くでしょう。
もっといい実装方法があるか
こちらの記事では、関数をつくって次のように実装しています。
def fizzBuzz(i: Int): String = { val fizz = i % 3 == 0 val buzz = i % 5 == 0 if (fizz && buzz) "FizzBuzz" else if (fizz) "Fizz" else if (buzz) "Buzz" else i.toString() } for (i <- 1 to 99) println(fizzBuzz(i))
さらにScalaっぽく書くパターンとして、次のように処理をチェーンするような書き方があります。
def fizzBuzz(i: Int) = { 1 to i } map { case i if i % 15 == 0 => "FizzBuzz" case i if i % 3 == 0 => "Fizz" case i if i % 5 == 0 => "Buzz" case _ => i } foreach { s => println(s) } fizzBuzz(100)
まずリストを作った上で、その要素をmapで加工し、最後に出力の処理を行います。
最後はmatch文を用いた実装です。こちらが最もシンプルでわかりやすいですね。
def fizzBuzz(i: Int) = i match { case i if i % 15 == 0 => "FizzBuzz" case i if i % 3 == 0 => "Fizz" case i if i % 5 == 0 => "Buzz" case _ => i.toString() }