FizzBuzz問題を解いていて気付いたのですが、Rにバグがあるかも知れません。と思ったら、無かったです。
ちょっと紛らわしいコードを書きます。ベクターに添字をすることで、ベクターの一部分の文字列を取得しているのですが、1から11まで一度に計算したときと、1から12まで一度に計算したときで、10番目の結果が変化します。
f <- function(i){
l <- c("Fizz", "Buzz", "FizzBuzz")
ii <- (0==i%%5)*2 + (0==i%%3)*1
return(ifelse(0<ii, l[ii], i))
}
10番目に注目して、f(1:11)とf(1:12)を比較してみましょう。
> f(1:11)
[1] "1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11"
> f(1:12)
[1] "1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Fizz" "11" "Fizz"
場合によっては致命的ですよね、これ。でもバグでは無いみたいです。
ifelse()関数は第1項、第2項、第3項が独立に評価された上で、第1項と比較して第2項と第3項の長さが短い場合、自動的に繰り返して延長されます。
具体的には、l[ii]は、f(1:11)のときはc("Fizz","Buzz","Fizz","Fizz","Buzz")になり、f(1:11)のときはc("Fizz","Buzz","Fizz","Fizz","Buzz","Fizz")とります。ifelse()で短い系列は循環して結合されるため、以下のようになるわけですね。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|
正解 | Fizz | Buzz | Fizz | Fizz | Buzz | |||||
f(1:11) | Fizz | Buzz | Fizz | Fizz | Buzz | Fizz | Buzz | Fizz | Fizz | Buzz |
f(1:12) | Fizz | Buzz | Fizz | Fizz | Buzz | Fizz | Fizz | Buzz | Fizz | Fizz |
だから、ベクターの添え字になる変数iiが必ず0以上の値になる場合は、問題は発生しません(
RでFizzBuzz問題を高速化)。