ようこそ。睡眠不足なプログラマのチラ裏です。

F#で逆FizzBuzz問題

元ネタ
FizzBuzz問題 (Inverse FizzBuzz) - 猫とC#について書くmatarilloの雑記
http://d.hatena.ne.jp/matarillo/20120515/p1

 

面白いですねえ。




無理矢理詰め込んでツイートしたけど、F#で140文字ゴルフプログラミングとか割と無茶ですから!(白目

F#で逆FizzBuzz問題

二番煎じというのは、面白さ半減どころかほぼ面白みなし!的な雰囲気がありますが、
ゴルフなスニペットだけ置いておくのもアレなので実装例全体をのっけとく。

open System

let fzbz lst = 
  let isFizzBuzz x = if x%3 = 0 || x%5 =0 then true else false
  let toFizzBuzz x = 
    (x%3,x%5) |> function
    |0,0 -> "fizzbuzz"
    |0,_ -> "fizz" 
    |_ -> "buzz"
  [for x in lst do if isFizzBuzz(x) then yield toFizzBuzz(x)]

let range n = [1..n] |> List.map (fun x -> [x..n] |> List.map (fun y -> x,y)) |> List.collect id
                     |> List.sortBy (fun (a,b) -> b - a) 
let inverses x = range 100 |> List.find (fun (a,b) -> fzbz [a..b] = x)

printfn "%A" <| inverses ["fizz"]               // (3,3)
printfn "%A" <| inverses ["buzz"]               // (5,5)
printfn "%A" <| inverses ["fizz";"fizz";"buzz"] // (6,10)
printfn "%A" <| inverses ["fizz";"buzz"]        // (9,10)
printfn "%A" <| inverses ["buzz";"fizz"]        // (5,6)
printfn "%A" <| inverses ["fizz";"buzz";"fizz"] // (3,6)
printfn "%A" <| inverses ["fizz";"fizz"]        // (6,9)
printfn "%A" <| inverses ["fizz";"fizzbuzz"]    // (12,15)

Console.ReadLine () |> ignore

元ネタの元ネタのScalaでの解説は、確かにストーリー的には面白いものになっているけど、プログラムとしては結構無駄な計算が多くて、それってどうなの?ってー感じがしないこともなくもない。上記のように、探索対象を範囲が狭くて小さい順に先にソートしてから探索して、最初に一致したものを返すという考え方の方が、計算量も少なくなりますし自然ですね。


 
いげ太さんに禿同と言わざるを得ない。まぁ、抽象化の超パワーを無視することは(おれは)できないけどね!
ちなみに、F#は書き味のほうも最高峰レベルなので使ったら気に入ること間違いなしだよっウフフオッケー☆





追記:5/17
対象が見つからない場合も考慮したやつ

open System

let fzbz lst = 
  let isFizzBuzz x = if x%3 = 0 || x%5 =0 then true else false
  let toFizzBuzz x = 
    (x%3,x%5) |> function
    |0,0 -> "fizzbuzz"
    |0,_ -> "fizz" 
    |_ -> "buzz"
  [for x in lst do if isFizzBuzz(x) then yield toFizzBuzz(x)]

let range n = [1..n] |> List.map (fun x -> [x..n] |> List.map (fun y -> x,y)) |> List.collect id
                     |> List.sortBy (fun (a,b) -> b - a) 
let inverses = function
| [] -> None
| x  -> range 100 |> List.tryFind (fun (a,b) -> fzbz [a..b] = x)

let print = function
| Some x -> printfn "%A" <| x
| None   -> printfn "None"

print <| inverses ["fizz"]                // (3,3)
print <| inverses ["buzz"]                // (5,5)
print <| inverses ["fizz";"fizz";"buzz"]  // (6,10)
print <| inverses ["fizz";"buzz"]         // (9,10)
print <| inverses ["buzz";"fizz"]         // (5,6)
print <| inverses ["fizz";"buzz";"fizz"]  // (3,6)
print <| inverses ["fizz";"fizz"]         // (6,9)
print <| inverses ["fizz";"fizzbuzz"]     // (12,15)
print <| inverses []                      // None
print <| inverses ["orz"]                 // None
print <| inverses ["fizzbuzz";"fizzbuzz"] // None

Console.ReadLine () |> ignore