何日めか忘れたけどFizzBuzzアドベントカレンダーです。
今回のコンセプト
- if文を使わない
- 剰余を使わない
- 実行文とモジュール定義文以外全部ワンライナーのdef文
- その他無駄なこだわり
ソースコード
fizz_buzz.ex
defmodule FizzBuzz do
def fizzBuzz(num), do: _notFB(_fizz(oneDigit(Integer.to_charlist(num))) <> _buzz(_getLastDigit(Integer.to_charlist(num))) , num)
def sumDigit([head | []]), do: head - 48
def sumDigit([head | tail]), do: head - 48 + sumDigit(tail)
def oneDigit([head | []]), do: head - 48
def oneDigit(list), do: oneDigit(Integer.to_charlist(sumDigit(list)))
def _fizz(3), do: "Fizz"
def _fizz(6), do: "Fizz"
def _fizz(9), do: "Fizz"
def _fizz(_), do: ""
def _getLastDigit([head | []]), do: head - 48
def _getLastDigit([_ | tail]), do: _getLastDigit(tail)
def _buzz(5), do: "Buzz"
def _buzz(0), do: "Buzz"
def _buzz(_), do: ""
def _notFB("", num), do: Integer.to_charlist(num)
def _notFB(some, _), do: some
end
Enum.map(1..100, fn(x) -> IO.puts FizzBuzz.fizzBuzz(x) end)
解説
Elixirで書きました。If文を使わない、の部分はパターンマッチで対処しています。
上から読んでいきます。
FizzBuzz本体
def fizzBuzz(num), do: _notFB(_fizz(oneDigit(Integer.to_charlist(num))) <> _buzz(_getLastDigit(Integer.to_charlist(num))) , num)
他で定義した関数をつなげて実行するだけです。
Fizz
def sumDigit([head | []]), do: head - 48
def sumDigit([head | tail]), do: head - 48 + sumDigit(tail)
def oneDigit([head | []]), do: head - 48
def oneDigit(list), do: oneDigit(Integer.to_charlist(sumDigit(list)))
def _fizz(3), do: "Fizz"
def _fizz(6), do: "Fizz"
def _fizz(9), do: "Fizz"
def _fizz(_), do: ""
今回は剰余を使わない、という条件があるため、各桁の和が3の倍数であれば3の倍数という性質を利用しています。Elixirには、Charlistは、int型のlistと同じ型という性質があるため、一文字ずつ48を引いて(ASCII -> int)再帰的に処理しています。
Buzz
def _buzz(5), do: "Buzz"
def _buzz(0), do: "Buzz"
def _buzz(_), do: ""
def _notFB("", num), do: Integer.to_charlist(num)
def _notFB(some, _), do: some
こちらは単純に最後が5か0かで判断しています。
文字列の結合
def _notFB("", num), do: Integer.to_charlist(num)
def _notFB(some, _), do: some
今までの関数は、該当する場合、Fizzを該当しない場合Buzzを返していました。この関数で、から文字列でない場合はその文字列を、から文字列sの場合は数字を返却しています。
実行文
Enum.map(1..100, fn(x) -> IO.puts FizzBuzz.fizzBuzz(x) end)
なんのひねりもない繰り返しです。
まとめ
FizzBuzは楽しい