元コンサルでデータサイエンティスト

スタートアップでAI関連の事業開発をしています。元コンサルでデータサイエンティスト

【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」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。

ja.wikipedia.org


いや、ただの宴会ゲーム。難しそう。


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)

for文

Scalaにおけるfor文の書き方についてみていきます。

こんな感じです。簡単です。

$ for (s <- Array("a", "b", "c")) println(s)
 a
 b
 c



それでは前のセクションで学んだリストを使い、1から100を出力してみましょう。

$ for (s <- (1 to 100)) println(s)
 1
 2
 3
 4
 ..........
 
 99
 100


できました。
あとは条件分岐にしたがって、”Fizz” や “Buzz” を出力するようにしていきましょう。

if-else文 / match文

Scalaにおけるif-else条件分岐の書き方について確認していきます。

if-else文は次のように書きます。

$ val i = 3
$ if (i % 2 == 0) print("even") else print("odd")
 odd

また、他の言語のswitch文にあたる構文として、Scalaにはmatch文があります。

var num = 1
num match{
    case 1 => println("one")
    case 2 => println("two)
    case _ => println("other")
}


ScalaFizzBuzz問題を解く

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()
}



まとめ

ScalaFizzBuzz問題にチャレンジしてみました。Scalaの基本的なプログラミング構文を活用し、さまざまな実装パターンについて確認しました。Scalaは複雑なプログラミング言語であるというイメージがありましたが、意外にシンプルに書くことができました。引き続きScalaに関する記事を書いていきたいと思います。