1
0

More than 3 years have passed since last update.

【Kotlin】仕様変更に強い FizzBuzz

Last updated at Posted at 2020-07-11

ネタ元:「fizzbuzzについて思うこと」
TypeScript版:【TypeScript】仕様変更に強い FizzBuzz
更に仕様変更に強くした版:【Kotlin】更に仕様変更に強い FizzBuzz

FizzBuzz の、割る数、出力する文字列、変換規則の数や順番が変わっても
最小限のコード変更で済むようにする。

/**
 * FizzBuzz を行うためのクラス。
 * 
 * [invoke] 関数に数値を与えると対応する文字列を返す。
 */
class FizzBuzz private constructor(
    private val fizzBuzzMap: List<Pair<Int, String>>
) {
    /**
     * @param fizzBuzzMap 割る数と、
     *  それで割り切れたときに出力する文字列の組の列。
     */
    constructor(
        fizzBuzzMap: Iterable<Pair<Int, String>>
    ) : this(fizzBuzzMap.toList())

    /**
     * @param fizzBuzzMap 割る数と、
     *  それで割り切れたときに出力する文字列の組の列。
     */
    constructor (
        vararg fizzBuzzMap: Pair<Int, String>
    ) : this(fizzBuzzMap.toList())

    /** 与えられた数値に対応する文字列を返す。 */
    operator fun invoke(num: Int): String =
        fizzBuzzMap.asSequence()
            .mapNotNull { (divisor, str) ->
                if (num % divisor == 0) str
                else null
            }
            .joinToString("")
            .takeUnless { it.isEmpty() }
            ?: num.toString()
}

普通の FizzBuzz

/** 変換規則の定義。 */
val fizzBuzz = FizzBuzz(
    3 to "Fizz",
    5 to "Buzz"
)

fun main() {
    (1..15).asSequence()
        .map {
            fizzBuzz(it)
        }.forEach {
            println(it)
        }
}

出力

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

割る数と出力する文字列を変更

/** 変換規則の定義。 */
val fizzBuzz = FizzBuzz(
    7 to "Foo",
    2 to "Bar"
)

// main 関数は同じなので省略

出力

1
Bar
3
Bar
5
Bar
Foo
Bar
9
Bar
11
Bar
13
FooBar
15

こんなことも

val fizzBuzz = FizzBuzz(
    1 to "<",
    3 to "Fizz",
    5 to "Buzz",
    1 to ">"
)

// main 関数は同じなので省略

出力

<>
<>
<Fizz>
<>
<Buzz>
<Fizz>
<>
<>
<Fizz>
<Buzz>
<>
<Fizz>
<>
<>
<FizzBuzz>

/以上

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0