我目前正在学习F#并尝试过(非常简单的)FizzBuzz示例.
这是我最初的尝试:
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
Run Code Online (Sandbox Code Playgroud)
什么解决方案可以更优雅/简单/更好(解释原因)使用F#来解决这个问题?
注意:FizzBuzz问题通过数字1到100,每3个打印Fizz,每5个打印Buzz,3和5的每个倍数打印FizzBuzz.否则,简单显示数字.
谢谢 :)
Bri*_*ian 53
我想你已经拥有了"最好的"解决方案.
如果你想展示更多功能性/ F#主义,你可以做例如
[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")
Run Code Online (Sandbox Code Playgroud)
并使用列表,序列,地图,iter,模式和部分应用程序.
[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!
Run Code Online (Sandbox Code Playgroud)
Tom*_*cek 24
我的例子只是对'ssp'发布的代码的一个小改进.它使用参数化的活动模式(以除数作为参数).这是一个更深入的解释:
下面定义了一个活动模式,我们稍后可以在match
表达式中使用它来测试值i是否可以被值整除divisor.当我们写:
match 9 with
| DivisibleBy 3 -> ...
Run Code Online (Sandbox Code Playgroud)
...这意味着值'9'将传递给以下函数,i并且值3将作为传递divisor.这个名称(|DivisibleBy|_|)是一种特殊的语法,这意味着我们正在声明一个活动模式(并且名称可以出现在
match左侧->.该|_|位意味着模式可能失败(我们的示例在值不能被整除时失败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
Run Code Online (Sandbox Code Playgroud)
现在我们可以迭代所有数字,并使用match(或使用Seq.iter或其他答案中显示的其他技术)将它们与模式(我们的活动模式)匹配:
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
Run Code Online (Sandbox Code Playgroud)
有关F#活动模式的更多信息,请参阅MSDN文档链接.我认为,如果删除所有注释,代码将比原始版本更具可读性.它显示了一些非常有用的技巧:-),但在你的情况下,任务相对容易......
ssp*_*ssp 12
还有一种F#风格的解决方案(即使用Active Patterns):
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
Run Code Online (Sandbox Code Playgroud)
Tom*_*cek 10
添加一个可能的答案 - 这是另一种没有模式匹配的方法.它使用的事实是Fizz + Buzz = FizzBuzz,所以你实际上并不需要测试所有三种情况,你只需要查看它是否可被3整除(然后打印"Fizz")并查看它是否可被5整除(然后打印"Buzz")最后,打印一个新行:
for i in 1..100 do
for divisor, str in [ (3, "Fizz"); (5; "Buzz") ] do
if i % divisor = 0 then printf str
printfn ""
Run Code Online (Sandbox Code Playgroud)
嵌套for循环assignes 3和"嘶嘶声",以divisor与str在第一次迭代,然后在第二次迭代的第二对值.好处是,当值可以被7整除时,你可以很容易地添加"Jezz"的打印......如果解决方案的可扩展性是一个问题!
还有一个:
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)
Run Code Online (Sandbox Code Playgroud)
我发现这是一个更可读的答案编辑受到其他人的启发
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")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4369 次 |
| 最近记录: |