f# fizzbuzz

Cómo codificar Fizzbuzz en F#



(10)

Creo que ya tienes la "mejor" solución.

Si desea mostrar más funcional / F # -ismos, podría hacer, por ejemplo

[1..100] |> Seq.map (function | x when x%5=0 && x%3=0 -> "FizzBuzz" | x when x%3=0 -> "Fizz" | x when x%5=0 -> "Buzz" | x -> string x) |> Seq.iter (printfn "%s")

y use listas, secuencias, mapas, iter, patrones y aplicaciones parciales.

[1..100] // I am the list of numbers 1-100. // F# has immutable singly-linked lists. // List literals use square brackets. |> // I am the pipeline operator. // "x |> f" is just another way to write "f x". // It is a common idiom to "pipe" data through // a bunch of transformative functions. Seq.map // "Seq" means "sequence", in F# such sequences // are just another name for IEnumerable<T>. // "map" is a function in the "Seq" module that // applies a function to every element of a // sequence, returning a new sequence of results. (function // The function keyword is one way to // write a lambda, it means the same // thing as "fun z -> match z with". // "fun" starts a lambda. // "match expr with" starts a pattern // match, that then has |cases. | x when x%5=0 && x%3=0 // I''m a pattern. The pattern is "x", which is // just an identifier pattern that matches any // value and binds the name (x) to that value. // The "when" clause is a guard - the pattern // will only match if the guard predicate is true. -> "FizzBuzz" // After each pattern is "-> expr" which is // the thing evaluated if the pattern matches. // If this pattern matches, we return that // string literal "FizzBuzz". | x when x%3=0 -> "Fizz" // Patterns are evaluated in order, just like // if...elif...elif...else, which is why we did // the ''divisble-by-both'' check first. | x when x%5=0 -> "Buzz" | x -> string x) // "string" is a function that converts its argument // to a string. F# is statically-typed, so all the // patterns have to evaluate to the same type, so the // return value of the map call can be e.g. an // IEnumerable<string> (aka seq<string>). |> // Another pipeline; pipe the prior sequence into... Seq.iter // iter applies a function to every element of a // sequence, but the function should return "unit" // (like "void"), and iter itself returns unit. // Whereas sequences are lazy, "iter" will "force" // the sequence since it needs to apply the function // to each element only for its effects. (printfn "%s") // F# has type-safe printing; printfn "%s" expr // requires expr to have type string. Usual kind of // %d for integers, etc. Here we have partially // applied printfn, it''s a function still expecting // the string, so this is a one-argument function // that is appropriate to hand to iter. Hurrah!

Actualmente estoy aprendiendo F # y he probado (un extremadamente) simple ejemplo de FizzBuzz.

Este es mi intento inicial:

for x in 1..100 do if x % 3 = 0 && x % 5 = 0 then printfn "FizzBuzz" elif x % 3 = 0 then printfn "Fizz" elif x % 5 = 0 then printfn "Buzz" else printfn "%d" x

¿Qué soluciones podrían ser más elegantes / simples / mejores (explicando por qué) usando F # para resolver este problema?

Nota: El problema de FizzBuzz está pasando por los números 1 a 100 y cada múltiplo de 3 impresiones Fizz, cada múltiplo de 5 impresiones Buzz, cada múltiplo de 3 y 5 copias FizzBuzz. De lo contrario, se muestra el número simple.

Gracias :)


Sin embargo, una solución en estilo F # (es decir, con el uso de Patrones Activos):

let (|P3|_|) i = if i % 3 = 0 then Some i else None let (|P5|_|) i = if i % 5 = 0 then Some i else None let f = function | P3 _ & P5 _ -> printfn "FizzBuzz" | P3 _ -> printfn "Fizz" | P5 _ -> printfn "Buzz" | x -> printfn "%d" x Seq.iter f {1..100} //or for i in 1..100 do f i


Mi ejemplo es solo una pequeña mejora con respecto al código publicado por ''ssp''. Utiliza patrones activos parametrizados (que toman el divisor como argumento). Aquí hay una explicación más detallada:

A continuación, se define un patrón activo que luego podemos utilizar en la expresión de match para comprobar si un valor i es divisible por un divisor valores. Cuando escribimos:

match 9 with | DivisibleBy 3 -> ...

... significa que el valor ''9'' pasará a la siguiente función como i y el valor 3 pasará como divisor . El nombre (|DivisibleBy|_|) es una sintaxis especial, lo que significa que estamos declarando un patrón activo (y el nombre puede aparecer en la match en el lado izquierdo de -> . The |_| bit significa que el patrón puede fallar (nuestro ejemplo falla cuando el valor no es divisible por divisor )

let (|DivisibleBy|_|) divisor i = // If the value is divisible, then we return ''Some()'' which // represents that the active pattern succeeds - the ''()'' notation // means that we don''t return any value from the pattern (if we // returned for example ''Some(i/divisor)'' the use would be: // match 6 with // | DivisibleBy 3 res -> .. (res would be asigned value 2) // None means that pattern failed and that the next clause should // be tried (by the match expression) if i % divisor = 0 then Some () else None

Ahora podemos iterar sobre todos los números y Seq.iter con los patrones (nuestro patrón activo) usando match (o usando Seq.iter o alguna otra técnica como se muestra en otras respuestas):

for i in 1..100 do match i with // & allows us to run more than one pattern on the argument ''i'' // so this calls ''DivisibleBy 3 i'' and ''DivisibleBy 5 i'' and it // succeeds (and runs the body) only if both of them return ''Some()'' | DivisibleBy 3 & DivisibleBy 5 -> printfn "FizzBuzz" | DivisibleBy 3 -> printfn "Fizz" | DivisibleBy 5 -> printfn "Buzz" | _ -> printfn "%d" i

Para obtener más información sobre los patrones activos F #, aquí hay un enlace de documentación de MSDN . Creo que si elimina todos los comentarios, el código será un poco más legible que la versión original. Muestra algunos trucos bastante útiles :-), pero en tu caso, la tarea es relativamente fácil ...


Para agregar una respuesta más, aquí hay otro enfoque sin coincidencia de patrones. Utiliza el hecho de que Fizz + Buzz = FizzBuzz , por lo que en realidad no necesita probar los tres casos, solo necesita ver si es divisible por 3 (luego imprimir "Fizz") y también ver si es divisible por 5 (luego imprima "Buzz") y, finalmente, imprima una nueva línea:

for i in 1..100 do for divisor, str in [ (3, "Fizz"); (5; "Buzz") ] do if i % divisor = 0 then printf str printfn ""

El ciclo for anidado asigna 3 y "Fizz" a divisor y str en la primera iteración y luego al segundo par de valores en la segunda iteración. El beneficio es que puede agregar fácilmente la impresión de "Jezz" cuando el valor es divisible por 7 :-) ... ¡en caso de que la extensibilidad de la solución sea una preocupación!


Aquí está mi versión:

//initialize array a with values from 1 to 100 let a = Array.init 100 (fun x -> x + 1) //iterate over array and match *indexes* x Array.iter (fun x -> match x with | _ when x % 15 = 0 -> printfn "FizzBuzz" | _ when x % 5 = 0 -> printfn "Buzz" | _ when x % 3 = 0 -> printfn "Fizz" | _ -> printfn "%d" x ) a

Este es mi primer programa en F #.

No es perfecto, pero creo que alguien que comienza a aprender F # (como yo :) puede descubrir lo que sucede aquí bastante rápido.

Sin embargo, me pregunto ¿cuál es la diferencia entre la coincidencia con cualquier _ o x en la coincidencia de patrones anterior?


Aquí hay una versión que hace hincapié en una lista tuple genérica de carbonaciones:

let carbonations = [(3, "Spizz") ; (5, "Fuzz"); (15, "SpizzFuzz"); (30, "DIZZZZZZZZ"); (18, "WHIIIIII")] let revCarbonated = carbonations |> List.sort |> List.rev let carbonRoute someCarbonations findMe = match(List.tryFind (fun (x,_) -> findMe % x = 0) someCarbonations) with | Some x -> printfn "%d - %s" findMe (snd x) | None -> printfn "%d" findMe let composeCarbonRoute = carbonRoute revCarbonated [1..100] |> List.iter composeCarbonRoute


No pude encontrar una solución funcional que no incluyera pruebas para i% 15 = 0 . Siempre sentí que no hacer pruebas para eso es parte de esta asignación "estúpida". Tenga en cuenta que esto probablemente no es idiomático F # ya que es mi primer programa en el idioma.

for n in 1..100 do let s = seq { if n % 3 = 0 then yield "Fizz" if n % 5 = 0 then yield "Buzz" } if Seq.isEmpty s then printf "%d"n printfn "%s"(s |> String.concat "")


Aquí hay uno más:

let fizzy num = match num%3, num%5 with | 0,0 -> "fizzbuzz" | 0,_ -> "fizz" | _,0 -> "buzz" | _,_ -> num.ToString() [1..100] |> List.map fizzy |> List.iter (fun (s:string) -> printfn "%s" s)


Encuentro que esto es un poco más legible. La respuesta editada fue inspirada un poco por los otros.

let FizzBuzz n = match n%3,n%5 with | 0,0 -> "FizzBuzz" | 0,_ -> "Fizz" | _,0 -> "Buzz" | _,_ -> string n [1..100] |> Seq.map (fun n -> FizzBuzz n) |> Seq.iter (printfn "%s")


No me gustan todas estas cadenas repetidas, aquí está el mío:

open System let ar = [| "Fizz"; "Buzz"; |] [1..100] |> List.map (fun i -> match i % 3 = 0, i % 5 = 0 with | true, false -> ar.[0] | false, true -> ar.[1] | true, true -> ar |> String.Concat | _ -> string i |> printf "%s/n" ) |> ignore